composio-llamaindex 0.0.1__tar.gz

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.

Potentially problematic release.


This version of composio-llamaindex might be problematic. Click here for more details.

@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.1
2
+ Name: composio-llamaindex
3
+ Version: 0.0.1
4
+ Summary: Provides integrations skill with 50+ services in LlamaIndex
5
+ Home-page: https://github.com/SamparkAI/llama-composio
6
+ Author: Karan
7
+ Author-email: karan@composio.dev
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: requests
14
+ Requires-Dist: jsonschema
15
+ Requires-Dist: argparse
16
+ Requires-Dist: llama_index
17
+ Requires-Dist: nest_asyncio
18
+ Requires-Dist: beaupy===3.7.2
19
+
20
+ Composio <> Llama Indxex
21
+ Use Composio to get an array of tools with your llamaindex agent.
22
+
23
+ # Usage
24
+ Inside your llamaindex codebase:
25
+ ```
26
+ from composio_llama import ComposioToolset
27
+ toolset = ComposioToolset(<token>)
28
+ agent = OpenAIAgent.from_tools(toolset.to_tool_list(), llm=llm, verbose=True)
29
+ ...
30
+ ```
31
+
32
+
@@ -0,0 +1,13 @@
1
+ Composio <> Llama Indxex
2
+ Use Composio to get an array of tools with your llamaindex agent.
3
+
4
+ # Usage
5
+ Inside your llamaindex codebase:
6
+ ```
7
+ from composio_llama import ComposioToolset
8
+ toolset = ComposioToolset(<token>)
9
+ agent = OpenAIAgent.from_tools(toolset.to_tool_list(), llm=llm, verbose=True)
10
+ ...
11
+ ```
12
+
13
+
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env python
2
+
3
+ import argparse
4
+ import webbrowser
5
+ import requests
6
+ import json
7
+ import os
8
+ from lib.storage import save_user_id, get_user_id
9
+ import time
10
+ from beaupy.spinners import Spinner, BARS
11
+
12
+ COMPOSIO_TOKEN = 'ghp_1J2g3h4i5j6k7l8m9n0o33'
13
+ BASE_URL = "https://hermes-production-6901.up.railway.app/api"
14
+
15
+ def auth_tool(args):
16
+ user_id = get_user_id()
17
+ if user_id is None:
18
+ print("Error: No authenticated user found. Please authenticate first.")
19
+ return
20
+ print(f"Authenticating tool: {args.tool_name} for User ID: {user_id}")
21
+ url = f"{BASE_URL}/user/auth"
22
+ payload = json.dumps({
23
+ "endUserID": user_id,
24
+ "provider": {
25
+ "name": args.tool_name,
26
+ "scope": [
27
+ "user.email",
28
+ "user.profile"
29
+ ]
30
+ },
31
+ "redirectURIClient": "https://composio.dev/"
32
+ })
33
+ headers = {
34
+ 'X_COMPOSIO_TOKEN': COMPOSIO_TOKEN,
35
+ 'Content-Type': 'application/json'
36
+ }
37
+ response = requests.request("POST", url, headers=headers, data=payload)
38
+ if response.status_code == 200:
39
+ auth_url = response.json().get('providerAuthURL')
40
+ connReqID = response.json().get('connectionReqId')
41
+ print(f"Auth URL: {auth_url}")
42
+ print(f"Connection Request ID: {connReqID}")
43
+ webbrowser.open(auth_url)
44
+ else:
45
+ print("Failed to authenticate tool.")
46
+ spinner = Spinner(BARS, f"Authenticating you...")
47
+ spinner.start()
48
+
49
+ while True: # Loop forever
50
+ status_check_url = f"{BASE_URL}/auth/{connReqID}/status"
51
+ status_payload = json.dumps({})
52
+ status_headers = {
53
+ 'X_COMPOSIO_TOKEN': COMPOSIO_TOKEN,
54
+ 'Content-Type': 'application/json',
55
+ }
56
+ response = requests.request("GET", status_check_url, headers=status_headers, data=status_payload)
57
+ status_data = response.json()
58
+ status = status_data.get('status')
59
+ if status == 'PENDING' or status == 'STARTED':
60
+ time.sleep(1) # Wait for 5 seconds before retrying
61
+ else:
62
+ print(f"Authentication status: {status_data.get('status')}")
63
+ break
64
+
65
+ spinner.stop()
66
+
67
+ def list_tools(args):
68
+ user_id = get_user_id()
69
+ if user_id is None:
70
+ print("Error: No authenticated user found. Please authenticate first.")
71
+ return
72
+ print(f"Fetching tools for User ID: {user_id}...")
73
+ url = f"{BASE_URL}/all_tools"
74
+ headers = {
75
+ 'X_COMPOSIO_TOKEN': COMPOSIO_TOKEN,
76
+ 'X_ENDUSER_ID': user_id
77
+ }
78
+ response = requests.post(url, headers=headers, json={
79
+ "skip": 0,
80
+ "limit": 1000,
81
+ "actions": True,
82
+ "triggers": False
83
+ })
84
+ if response.status_code == 200:
85
+ tools_data = response.json()
86
+ for tool in tools_data.get('tools', []):
87
+ print(f"Name: {tool['Name']}, Description: {tool['Description']}")
88
+ if args.auth and tool['Authentication']['isAuthenticated'] == "False":
89
+ print(f"Tool {tool['Name']} requires authentication.")
90
+ else:
91
+ print("Failed to fetch tools.")
92
+
93
+ def auth(args):
94
+ if not args.email:
95
+ print("Error: Email ID is required for authentication.")
96
+ return
97
+ print(f"Authenticating {args.email}...")
98
+ url = f"{BASE_URL}/user/create/{args.email}"
99
+ headers = {
100
+ 'X_COMPOSIO_TOKEN': COMPOSIO_TOKEN
101
+ }
102
+ response = requests.post(url, headers=headers)
103
+ if response.status_code == 200:
104
+ user_id = response.json().get('userId')
105
+ print(f"Authenticated successfully. User ID: {user_id}")
106
+ save_user_id(user_id)
107
+ else:
108
+ print("Authentication failed.")
109
+
110
+ def main():
111
+ parser = argparse.ArgumentParser(description='Composio CLI')
112
+ subparsers = parser.add_subparsers(help='commands')
113
+
114
+ # Auth command
115
+ auth_parser = subparsers.add_parser('auth', help='Authenticate user')
116
+ auth_parser.add_argument('email', type=str, help='User email ID for authentication')
117
+ auth_parser.set_defaults(func=auth)
118
+
119
+ # List tools command
120
+ list_tools_parser = subparsers.add_parser('list_tools', help='List tools')
121
+ list_tools_parser.add_argument('--auth', action='store_true', help='List only authenticated tools')
122
+ list_tools_parser.set_defaults(func=list_tools)
123
+
124
+ # Auth tool command
125
+ auth_tool_parser = subparsers.add_parser('auth_tool', help='Authenticate a tool')
126
+ auth_tool_parser.add_argument('tool_name', type=str, help='Name of the tool to authenticate')
127
+ auth_tool_parser.set_defaults(func=auth_tool)
128
+
129
+ args = parser.parse_args()
130
+ if hasattr(args, 'func'):
131
+ args.func(args)
132
+ else:
133
+ parser.print_help()
134
+
135
+ if __name__ == '__main__':
136
+ main()
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.1
2
+ Name: composio-llamaindex
3
+ Version: 0.0.1
4
+ Summary: Provides integrations skill with 50+ services in LlamaIndex
5
+ Home-page: https://github.com/SamparkAI/llama-composio
6
+ Author: Karan
7
+ Author-email: karan@composio.dev
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: requests
14
+ Requires-Dist: jsonschema
15
+ Requires-Dist: argparse
16
+ Requires-Dist: llama_index
17
+ Requires-Dist: nest_asyncio
18
+ Requires-Dist: beaupy===3.7.2
19
+
20
+ Composio <> Llama Indxex
21
+ Use Composio to get an array of tools with your llamaindex agent.
22
+
23
+ # Usage
24
+ Inside your llamaindex codebase:
25
+ ```
26
+ from composio_llama import ComposioToolset
27
+ toolset = ComposioToolset(<token>)
28
+ agent = OpenAIAgent.from_tools(toolset.to_tool_list(), llm=llm, verbose=True)
29
+ ...
30
+ ```
31
+
32
+
@@ -0,0 +1,15 @@
1
+ README.md
2
+ composio-llamaindex
3
+ pyproject.toml
4
+ setup.py
5
+ composio_llamaindex.egg-info/PKG-INFO
6
+ composio_llamaindex.egg-info/SOURCES.txt
7
+ composio_llamaindex.egg-info/dependency_links.txt
8
+ composio_llamaindex.egg-info/requires.txt
9
+ composio_llamaindex.egg-info/top_level.txt
10
+ lib/__init__.py
11
+ lib/composio_tool_spec.py
12
+ lib/composio_toolset.py
13
+ lib/openapi_tool_spec.py
14
+ lib/storage.py
15
+ lib/test_composio_tool_spec.py
@@ -0,0 +1,6 @@
1
+ requests
2
+ jsonschema
3
+ argparse
4
+ llama_index
5
+ nest_asyncio
6
+ beaupy===3.7.2
@@ -0,0 +1,3 @@
1
+ from .composio_tool_spec import ComposioToolSpec
2
+ from .composio_toolset import ComposioToolset
3
+ from .openapi_tool_spec import APIToolSpec
@@ -0,0 +1,86 @@
1
+ import json
2
+ from typing import Dict, Any, List, Union, Type
3
+ import logging
4
+ import requests
5
+ from inspect import Parameter, Signature
6
+ import types
7
+
8
+ from llama_index.core.tools.tool_spec.base import BaseToolSpec
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ BASE_URL = "https://hermes-production-6901.up.railway.app/api"
13
+
14
+ def map_composio_type_to_python(type_spec) -> Type:
15
+ if isinstance(type_spec, dict):
16
+ type_str = type_spec.get('type')
17
+ if type_str == 'string':
18
+ return str
19
+ elif type_str == 'number':
20
+ return float if '.' in str(type_spec.get('example', '')) else int
21
+ elif type_str == 'boolean':
22
+ return bool
23
+ # elif type_str == 'object':
24
+ # properties = type_spec.get('properties', {})
25
+ # required = type_spec.get('required', [])
26
+ # return Dict[str, Union[*tuple(map_composio_type_to_python(prop) for prop in properties.values()), Any]] if properties else Dict[str, Any]
27
+ # elif type_str == 'array':
28
+ # items_spec = type_spec.get('items', {})
29
+ # return List[map_composio_type_to_python(items_spec)] if items_spec else List[Any]
30
+ # Add more mappings as necessary
31
+ # Fallback or default type
32
+ return Any # Using Any for unspecified or complex types
33
+
34
+ class ComposioToolSpec(BaseToolSpec):
35
+ """Generic tool spec based on composio_tool.json schema."""
36
+
37
+ def __init__(self, tool_schema: str, composio_token: str, user_id: str) -> None:
38
+ """Initialize with composio tool schema."""
39
+ self.tool_schema = json.loads(tool_schema)
40
+ self.spec_functions = self._generate_spec_functions()
41
+
42
+ def _generate_spec_functions(self) -> List[str]:
43
+ """Generate spec functions based on the tools actions."""
44
+ spec_functions = []
45
+ for tool in self.tool_schema.get("tools", []):
46
+ for action in tool.get("Actions", []):
47
+ function_name = tool["Name"] + "_" + action["Id"]
48
+ spec_functions.append(function_name)
49
+ input_params = action["Signature"]["Input"]["properties"]
50
+ print("input_params:", input_params)
51
+ setattr(self, function_name, self._create_function(tool["Name"], action["Id"], function_name, action["Description"], input_params, action["Signature"]["Input"].get("required", [])))
52
+ return spec_functions
53
+
54
+ def _create_function(self, tool_name: str, action_id: str, function_name: str, description: str, input_params: Dict[str, Any], required_params: List[str] = []):
55
+ """Create a function for the given action with typed arguments."""
56
+
57
+ # Function template that uses **kwargs to accept any arguments and performs an actual API call.
58
+ def template_function(**kwargs) -> Dict[str, Any]:
59
+ missing_params = [param for param in input_params if param not in kwargs and param in required_params]
60
+ if missing_params:
61
+ return {"error": f"Missing required params: {missing_params}"}
62
+ params = {param: kwargs[param] for param in input_params if param in kwargs}
63
+ logger.info(f"Executing action {action_id} with {params}")
64
+
65
+ request_body = json.dumps(params)
66
+ response = requests.post(f"{BASE_URL}/{tool_name}/{action_id}", data=request_body, headers={'Content-Type': 'application/json'})
67
+ return response.json()
68
+
69
+ parameters = [
70
+ Parameter(
71
+ name=param,
72
+ kind=Parameter.POSITIONAL_OR_KEYWORD,
73
+ annotation=map_composio_type_to_python(input_params[param]),
74
+ # default=Parameter.empty if param in required_params else Parameter.default
75
+ )
76
+ for param in input_params
77
+ ]
78
+ new_sig = Signature(parameters, return_annotation=Dict[str, Any])
79
+
80
+ func = types.FunctionType(template_function.__code__, globals(), name=function_name, closure=template_function.__closure__)
81
+
82
+ # Assign the new signature to the function.
83
+ func.__signature__ = new_sig
84
+ func.__doc__ = description
85
+
86
+ return func
@@ -0,0 +1,43 @@
1
+ import json
2
+ import requests
3
+ from .composio_tool_spec import ComposioToolSpec
4
+ from llama_index.core.tools.tool_spec.base import BaseToolSpec
5
+ from .storage import get_user_id
6
+ from .composio_tool_spec import BASE_URL
7
+
8
+ COMPOSIO_TOKEN = "ghp_1J2g3h4i5j6k7l8m9n0o33"
9
+
10
+ class ComposioToolset(ComposioToolSpec):
11
+ def __init__(self):
12
+ self.user_id = get_user_id()
13
+ print(f"User ID: {self.user_id}")
14
+ self.authenticated_tools = self.get_authenticated_tools(self.user_id)
15
+ tools_schema = json.dumps({"tools": self.authenticated_tools}) # Combine all tools into a single schema
16
+ super().__init__(tools_schema, COMPOSIO_TOKEN, self.user_id)
17
+
18
+ def get_authenticated_tools(self, user_id: str):
19
+ print("Fetching tools...")
20
+ if user_id is None:
21
+ raise Exception("No authenticated user found. Please authenticate first.")
22
+
23
+ url = f"{BASE_URL}/all_tools"
24
+ headers = {
25
+ 'X_COMPOSIO_TOKEN': COMPOSIO_TOKEN,
26
+ 'X_ENDUSER_ID': user_id
27
+ }
28
+ response = requests.post(url, headers=headers, json={
29
+ "skip": 0,
30
+ "limit": 1000,
31
+ "actions": True,
32
+ "triggers": False
33
+ })
34
+ if response.status_code == 200:
35
+ tools_data = response.json()
36
+ authenticated_tools = [
37
+ tool for tool in tools_data.get('tools', [])
38
+ # if tool['Authentication']['isAuthenticated'] == "True"
39
+ ]
40
+ print("Authenticated tools:", authenticated_tools)
41
+ return authenticated_tools
42
+ else:
43
+ raise Exception("Failed to fetch tools.")
@@ -0,0 +1,99 @@
1
+ import os
2
+ import yaml
3
+ import requests
4
+ from inspect import Parameter, Signature
5
+ from typing import List, Dict, Any
6
+ import types
7
+ import logging
8
+ import nest_asyncio
9
+
10
+ from llama_index.core.tools.tool_spec.base import BaseToolSpec
11
+
12
+ nest_asyncio.apply()
13
+
14
+ os.environ["OPENAI_API_KEY"] = "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"
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ def map_openapi_type_to_python(type_spec):
19
+ if isinstance(type_spec, dict):
20
+ type_str = type_spec.get('type')
21
+ if type_str == 'string':
22
+ return str
23
+ # Add more mappings as necessary
24
+ # Fallback or default type
25
+ return str # or any other default type
26
+
27
+ class APIToolSpec(BaseToolSpec):
28
+ """Generic API tool spec based on OpenAPI schema."""
29
+
30
+ def __init__(self, api_schema: str) -> None:
31
+ """Initialize with OpenAPI schema."""
32
+ self.api_schema = yaml.safe_load(api_schema)
33
+ self.spec_functions = self._generate_spec_functions()
34
+
35
+ def _generate_spec_functions(self) -> List[str]:
36
+ """Generate spec functions based on the OpenAPI paths."""
37
+ spec_functions = []
38
+ for path, methods in self.api_schema.get("paths", {}).items():
39
+ for method, details in methods.items():
40
+ print("details:", details)
41
+ function_name = self._generate_function_name(path, method)
42
+ spec_functions.append(function_name)
43
+ request_body_params = self._extract_request_body_params(details)
44
+ setattr(self, function_name, self._create_function(path, method, details.get("summary", ""), request_body_params))
45
+ return spec_functions
46
+
47
+ @staticmethod
48
+ def _generate_function_name(path: str, method: str) -> str:
49
+ """Generate a function name based on the path and method."""
50
+ clean_path = path.strip("/").replace("/", "_")
51
+ return f"{method}_{clean_path}"
52
+
53
+ @staticmethod
54
+ def _extract_request_body_params(details: Dict[str, Any]) -> Dict[str, Any]:
55
+ """Extract request body parameters from the OpenAPI details."""
56
+ try:
57
+ return details['requestBody']['content']['application/json']['schema']['properties']
58
+ except KeyError:
59
+ return {}
60
+
61
+ def _create_function(self, path: str, method: str, description: str, request_body_params: Dict[str, Any]):
62
+ """Create a function for the given path and method with typed arguments."""
63
+
64
+ # Function template that uses **kwargs to accept any arguments and performs an actual API call.
65
+ def template_function(**kwargs) -> Dict[str, Any]:
66
+ missing_params = [param for param in request_body_params if param not in kwargs]
67
+ if missing_params:
68
+ return {"error": f"Missing required params: {missing_params}"}
69
+ params = {param: kwargs[param] for param in request_body_params}
70
+ logger.info(f"Executing {method.upper()} request to {path} with {params}")
71
+
72
+ # Actual API call
73
+ full_url = f"{self.api_schema['servers'][0]['url']}{path}"
74
+ headers = {'Content-Type': 'application/json'}
75
+ if method.lower() == 'post':
76
+ response = requests.post(full_url, json=params, headers=headers)
77
+ elif method.lower() == 'get':
78
+ response = requests.get(full_url, params=params, headers=headers)
79
+ else:
80
+ return {"error": f"Method {method.upper()} not supported"}
81
+ return response.json()
82
+
83
+ # Create parameters with types for the new function's signature.
84
+ parameters = [
85
+ Parameter(name=param, kind=Parameter.POSITIONAL_OR_KEYWORD, annotation=map_openapi_type_to_python(type_))
86
+ for param, type_ in request_body_params.items()
87
+ ]
88
+
89
+ # Create a new signature from the parameters including the return annotation.
90
+ new_sig = Signature(parameters, return_annotation=Dict[str, Any])
91
+
92
+ # Use types.FunctionType to create a new function with the desired signature.
93
+ func = types.FunctionType(template_function.__code__, globals(), "function", closure=template_function.__closure__)
94
+
95
+ # Assign the new signature to the function.
96
+ func.__signature__ = new_sig
97
+ func.__doc__ = description
98
+
99
+ return func
@@ -0,0 +1,15 @@
1
+ import json
2
+ import os
3
+
4
+
5
+ def save_user_id(user_id):
6
+ user_data = {'user_id': user_id}
7
+ with open('user_data.json', 'w') as outfile:
8
+ json.dump(user_data, outfile)
9
+
10
+ def get_user_id():
11
+ if os.path.exists('user_data.json'):
12
+ with open('user_data.json', 'r') as infile:
13
+ user_data = json.load(infile)
14
+ return user_data.get('user_id')
15
+ return None
@@ -0,0 +1,64 @@
1
+ import unittest
2
+ from .composio_tool_spec import ComposioToolSpec
3
+ from inspect import signature
4
+ from llama_index.agent.openai import OpenAIAgent
5
+ from llama_index.llms.openai import OpenAI
6
+
7
+
8
+ class TestComposioToolSpec(unittest.TestCase):
9
+ def setUp(self):
10
+ with open("lib/data/composio_tool.json", "r") as file:
11
+ self.tool_spec_json = file.read()
12
+ self.composio_tool_spec = ComposioToolSpec(self.tool_spec_json, "composio_token", "user_id")
13
+
14
+ def test_spec_functions_generation(self):
15
+ """Test if spec functions are generated correctly based on the tool schema."""
16
+ expected_functions = [
17
+ "Clickup_CreateFolderView",
18
+ "Slack_SendMessage",
19
+ "Slack_UpdateMessage",
20
+ "Slack_DeleteMessage",
21
+ "Github_CreateIssue"
22
+ ]
23
+ self.assertEqual(sorted(self.composio_tool_spec.spec_functions), sorted(expected_functions))
24
+
25
+ def test_function_signature(self):
26
+ """Test if a specific function has the correct signature based on the tool schema."""
27
+ send_message_func = getattr(self.composio_tool_spec, "Slack_SendMessage", None)
28
+ self.assertIsNotNone(send_message_func)
29
+ sign = send_message_func.__signature__
30
+ expected_params = ['channel', 'text']
31
+ actual_params = list(sign.parameters.keys())
32
+ self.assertEqual(expected_params, actual_params)
33
+ sig = signature(send_message_func)
34
+ expected_sig = "(channel: str, text: str) -> Dict[str, Any]"
35
+ self.assertEqual(str(sig), expected_sig)
36
+ description = send_message_func.__doc__
37
+ expected_desc = "Send a message to a channel or user"
38
+ self.assertEqual(description, expected_desc)
39
+
40
+ def test_missing_required_params(self):
41
+ """Test if the function correctly handles missing required parameters."""
42
+ send_message_func = getattr(self.composio_tool_spec, "Slack_SendMessage", None)
43
+ self.assertIsNotNone(send_message_func)
44
+ response = send_message_func(text="Hello, World!")
45
+ self.assertIn("error", response)
46
+ self.assertIn("Missing required params", response["error"])
47
+
48
+ def test_nested_request_signature(self):
49
+ """Test if the function correctly handles nested request body parameters."""
50
+ create_issue_func = getattr(self.composio_tool_spec, "Clickup_CreateFolderView", None)
51
+ self.assertIsNotNone(create_issue_func)
52
+ sig = signature(create_issue_func)
53
+ print("sig:", sig)
54
+
55
+ def test_agent(self):
56
+ """Test the agent vy spec."""
57
+ llm = OpenAI(model="gpt-4-turbo-preview")
58
+ agent = OpenAIAgent.from_tools(self.composio_tool_spec.to_tool_list(), llm=llm, verbose=True)
59
+ agent.chat("Hello, World!")
60
+
61
+
62
+
63
+ if __name__ == '__main__':
64
+ unittest.main()
@@ -0,0 +1,15 @@
1
+ [project]
2
+ dynamic = ["classifiers", "version", "readme", "authors", "requires-python", "description"]
3
+ dependencies = [
4
+ "requests",
5
+ "jsonschema",
6
+ "argparse",
7
+ "llama_index",
8
+ "nest_asyncio",
9
+ "beaupy===3.7.2"
10
+ ]
11
+ name = "composio-llamaindex"
12
+
13
+ [build-system]
14
+ requires = [ "setuptools>=42", "wheel"]
15
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ from setuptools import setup
2
+ import os
3
+
4
+ def get_current_dir():
5
+ return os.path.dirname(os.path.realpath(__file__))
6
+
7
+ def resolve_paths(*paths):
8
+ return os.path.join(*paths)
9
+
10
+ readme_path = resolve_paths(get_current_dir(), 'README.md')
11
+
12
+ setup(
13
+ name = 'composio-llamaindex',
14
+ version = '0.0.1',
15
+ author = 'Karan',
16
+ author_email = 'karan@composio.dev',
17
+ description = 'Provides integrations skill with 50+ services in LlamaIndex',
18
+ long_description = open(readme_path).read(),
19
+ long_description_content_type = 'text/markdown',
20
+ url = 'https://github.com/SamparkAI/llama-composio',
21
+ classifiers = [
22
+ 'Programming Language :: Python :: 3',
23
+ 'License :: OSI Approved :: Apache Software License',
24
+ 'Operating System :: OS Independent'
25
+ ],
26
+ python_requires = '>=3.7',
27
+ include_package_data = True,
28
+ scripts = ['composio-llamaindex'],
29
+ )