composio-langchain 0.1.40__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.
File without changes
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.1
2
+ Name: composio_langchain
3
+ Version: 0.1.40
4
+ Summary: Use Composio to get an array of tools with your LangChain agent.
5
+ Home-page: https://github.com/SamparkAI/composio_sdk
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: nest_asyncio
17
+ Requires-Dist: langchain===0.1.0
18
+ Requires-Dist: langchain-openai===0.0.2.post1
19
+ Requires-Dist: langchainhub==0.1.15
20
+ Requires-Dist: pydantic===2.6.4
21
+ Requires-Dist: composio_core===0.1.40
22
+
23
+ Composio <> LangChain
24
+ Use Composio to get an array of tools with your LangChain agent.
25
+
26
+ # Usage
27
+ Inside your LangChain codebase:
@@ -0,0 +1,5 @@
1
+ Composio <> LangChain
2
+ Use Composio to get an array of tools with your LangChain agent.
3
+
4
+ # Usage
5
+ Inside your LangChain codebase:
@@ -0,0 +1,2 @@
1
+ from .composio_tool_spec import ComposioToolset, client
2
+ from composio import Action, App
@@ -0,0 +1,117 @@
1
+ import types
2
+ from typing import List, Annotated
3
+ from .pydantic_utils import json_schema_to_model
4
+ from langchain_core.tools import StructuredTool
5
+ from composio import ComposioCore, App, Action
6
+ from typing import List
7
+ from inspect import Parameter, Signature
8
+ from pydantic import create_model, Field
9
+
10
+
11
+ schema_type_python_type_dict = {
12
+ 'string': str,
13
+ 'number': float,
14
+ 'boolean': bool,
15
+ 'integer': int,
16
+ }
17
+
18
+ fallback_values = {
19
+ 'string': "",
20
+ 'number': 0.0,
21
+ 'integer': 0.0,
22
+ 'boolean': False,
23
+ 'object': {},
24
+ 'array': []
25
+ }
26
+
27
+ def pydantic_model_from_param_schema(param_schema):
28
+ fields = {}
29
+ param_title = param_schema['title'].replace(" ", "")
30
+ required_props = param_schema.get('required', [])
31
+ schema_params_object = param_schema.get('properties', {})
32
+ for prop_name, prop_info in schema_params_object.items():
33
+ prop_type = prop_info["type"]
34
+ prop_title = prop_info['title'].replace(" ", "")
35
+ prop_default = prop_info.get('default', fallback_values[prop_type])
36
+ if prop_type in schema_type_python_type_dict:
37
+ signature_prop_type = schema_type_python_type_dict[prop_type]
38
+ else:
39
+ signature_prop_type = pydantic_model_from_param_schema(prop_info)
40
+
41
+ if prop_name in required_props:
42
+ fields[prop_name] = (signature_prop_type,
43
+ Field(...,
44
+ title=prop_title,
45
+ description=prop_info.get('description',
46
+ prop_info.get('desc',
47
+ prop_title))
48
+ ))
49
+ else:
50
+ fields[prop_name] = (signature_prop_type,
51
+ Field(title=prop_title,
52
+ default=prop_default
53
+ ))
54
+ fieldModel = create_model(param_title, **fields)
55
+ return fieldModel
56
+
57
+ def get_signature_format_from_schema_params(
58
+ schema_params
59
+ ):
60
+ parameters = []
61
+ required_params = schema_params.get('required', [])
62
+ schema_params_object = schema_params.get('properties', {})
63
+ for param_name, param_schema in schema_params_object.items():
64
+ param_type = param_schema['type']
65
+ param_title = param_schema['title'].replace(" ", "")
66
+
67
+ if param_type in schema_type_python_type_dict:
68
+ signature_param_type = schema_type_python_type_dict[param_type]
69
+ else:
70
+ signature_param_type = pydantic_model_from_param_schema(param_schema)
71
+
72
+ param_default = param_schema.get('default', fallback_values[param_type])
73
+ param_annotation = Annotated[signature_param_type, param_schema.get('description',
74
+ param_schema.get('desc',
75
+ param_title))]
76
+ param = Parameter(
77
+ name=param_name,
78
+ kind=Parameter.POSITIONAL_OR_KEYWORD,
79
+ annotation=param_annotation,
80
+ default=Parameter.empty if param_name in required_params else param_default
81
+ )
82
+ parameters.append(param)
83
+ return parameters
84
+
85
+
86
+ def ComposioTool(client : ComposioCore, action_schema: dict[str, any]) -> StructuredTool:
87
+ name = action_schema["name"]
88
+ description = action_schema["description"]
89
+ parameters = json_schema_to_model(action_schema["parameters"])
90
+ appName = action_schema["appName"]
91
+ func_params = get_signature_format_from_schema_params(action_schema["parameters"])
92
+ action_signature = Signature(parameters=func_params)
93
+ placeholder_function = lambda **kwargs: client.execute_action(client.get_action_enum(name, appName), kwargs)
94
+ action_func = types.FunctionType(
95
+ placeholder_function.__code__,
96
+ globals=globals(),
97
+ name=name,
98
+ closure=placeholder_function.__closure__
99
+ )
100
+ action_func.__signature__ = action_signature
101
+ action_func.__doc__ = description
102
+ return StructuredTool.from_function(
103
+ name=name,
104
+ description=description,
105
+ args_schema=parameters,
106
+ return_schema=True,
107
+ # TODO use execute action here
108
+ func = action_func
109
+ )
110
+
111
+ client = ComposioCore()
112
+
113
+ def ComposioToolset(apps: List[App] = [], actions: List[Action] = []) -> List[StructuredTool]:
114
+ if len(apps) >0 and len(actions) > 0:
115
+ raise ValueError("You must provide either a list of tools or a list of actions, not both")
116
+ actions_list = client.sdk.get_list_of_actions(apps, actions)
117
+ return [ComposioTool(client, action) for action in actions_list]
@@ -0,0 +1,91 @@
1
+ from langchain.pydantic_v1 import BaseModel, Field, create_model
2
+ from typing import Any, Dict, List, Optional, Type
3
+
4
+ def json_schema_to_model(json_schema: Dict[str, Any]) -> Type[BaseModel]:
5
+ """
6
+ Converts a JSON schema to a Pydantic BaseModel class.
7
+
8
+ Args:
9
+ json_schema: The JSON schema to convert.
10
+
11
+ Returns:
12
+ A Pydantic BaseModel class.
13
+ """
14
+
15
+ # Extract the model name from the schema title.
16
+ model_name = json_schema.get('title')
17
+
18
+ # Extract the field definitions from the schema properties.
19
+ field_definitions = {
20
+ name: json_schema_to_pydantic_field(name, prop, json_schema.get('required', []) )
21
+ for name, prop in json_schema.get('properties', {}).items()
22
+ }
23
+
24
+ # Create the BaseModel class using create_model().
25
+ return create_model(model_name, **field_definitions)
26
+
27
+ def json_schema_to_pydantic_field(name: str, json_schema: Dict[str, Any], required: List[str]) -> Any:
28
+ """
29
+ Converts a JSON schema property to a Pydantic field definition.
30
+
31
+ Args:
32
+ name: The field name.
33
+ json_schema: The JSON schema property.
34
+
35
+ Returns:
36
+ A Pydantic field definition.
37
+ """
38
+
39
+ # Get the field type.
40
+ type_ = json_schema_to_pydantic_type(json_schema)
41
+
42
+ # Get the field description.
43
+ description = json_schema.get('description')
44
+
45
+ # Get the field examples.
46
+ examples = json_schema.get('examples', [])
47
+
48
+ # Create a Field object with the type, description, and examples.
49
+ # The 'required' flag will be set later when creating the model.
50
+ return (type_, Field(description=description, examples=examples, default=... if name in required else None))
51
+
52
+ def json_schema_to_pydantic_type(json_schema: Dict[str, Any]) -> Any:
53
+ """
54
+ Converts a JSON schema type to a Pydantic type.
55
+
56
+ Args:
57
+ json_schema: The JSON schema to convert.
58
+
59
+ Returns:
60
+ A Pydantic type.
61
+ """
62
+
63
+ type_ = json_schema.get('type')
64
+
65
+ if type_ == 'string':
66
+ return str
67
+ elif type_ == 'integer':
68
+ return int
69
+ elif type_ == 'number':
70
+ return float
71
+ elif type_ == 'boolean':
72
+ return bool
73
+ elif type_ == 'array':
74
+ items_schema = json_schema.get('items')
75
+ if items_schema:
76
+ item_type = json_schema_to_pydantic_type(items_schema)
77
+ return List[item_type]
78
+ else:
79
+ return List
80
+ elif type_ == 'object':
81
+ # Handle nested models.
82
+ properties = json_schema.get('properties')
83
+ if properties:
84
+ nested_model = json_schema_to_model(json_schema)
85
+ return nested_model
86
+ else:
87
+ return Dict
88
+ elif type_ == 'null':
89
+ return Optional[Any] # Use Optional[Any] for nullable fields
90
+ else:
91
+ raise ValueError(f'Unsupported JSON schema type: {type_}')
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.1
2
+ Name: composio_langchain
3
+ Version: 0.1.40
4
+ Summary: Use Composio to get an array of tools with your LangChain agent.
5
+ Home-page: https://github.com/SamparkAI/composio_sdk
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: nest_asyncio
17
+ Requires-Dist: langchain===0.1.0
18
+ Requires-Dist: langchain-openai===0.0.2.post1
19
+ Requires-Dist: langchainhub==0.1.15
20
+ Requires-Dist: pydantic===2.6.4
21
+ Requires-Dist: composio_core===0.1.40
22
+
23
+ Composio <> LangChain
24
+ Use Composio to get an array of tools with your LangChain agent.
25
+
26
+ # Usage
27
+ Inside your LangChain codebase:
@@ -0,0 +1,12 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ composio_langchain/__init__.py
6
+ composio_langchain/composio_tool_spec.py
7
+ composio_langchain/pydantic_utils.py
8
+ composio_langchain.egg-info/PKG-INFO
9
+ composio_langchain.egg-info/SOURCES.txt
10
+ composio_langchain.egg-info/dependency_links.txt
11
+ composio_langchain.egg-info/requires.txt
12
+ composio_langchain.egg-info/top_level.txt
@@ -0,0 +1,9 @@
1
+ requests
2
+ jsonschema
3
+ argparse
4
+ nest_asyncio
5
+ langchain===0.1.0
6
+ langchain-openai===0.0.2.post1
7
+ langchainhub==0.1.15
8
+ pydantic===2.6.4
9
+ composio_core===0.1.40
@@ -0,0 +1 @@
1
+ composio_langchain
@@ -0,0 +1,18 @@
1
+ [project]
2
+ dynamic = ["classifiers", "version", "readme", "authors", "requires-python", "description"]
3
+ dependencies = [
4
+ "requests",
5
+ "jsonschema",
6
+ "argparse",
7
+ "nest_asyncio",
8
+ "langchain===0.1.0",
9
+ "langchain-openai===0.0.2.post1",
10
+ "langchainhub==0.1.15",
11
+ "pydantic===2.6.4",
12
+ "composio_core===0.1.40"
13
+ ]
14
+ name = "composio_langchain"
15
+
16
+ [build-system]
17
+ requires = [ "setuptools>=42", "wheel"]
18
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,31 @@
1
+ from setuptools import setup
2
+ import os
3
+
4
+
5
+ def get_current_dir():
6
+ return os.path.dirname(os.path.realpath(__file__))
7
+
8
+
9
+ def resolve_paths(*paths):
10
+ return os.path.join(*paths)
11
+
12
+
13
+ readme_path = resolve_paths(get_current_dir(), "README.md")
14
+
15
+ setup(
16
+ name="composio_langchain",
17
+ version="0.1.40",
18
+ author="Karan",
19
+ author_email="karan@composio.dev",
20
+ description="Use Composio to get an array of tools with your LangChain agent.",
21
+ long_description=open(readme_path).read(),
22
+ long_description_content_type="text/markdown",
23
+ url="https://github.com/SamparkAI/composio_sdk",
24
+ classifiers=[
25
+ "Programming Language :: Python :: 3",
26
+ "License :: OSI Approved :: Apache Software License",
27
+ "Operating System :: OS Independent",
28
+ ],
29
+ python_requires=">=3.7",
30
+ include_package_data=True,
31
+ )