langchain-arcade 0.1.2__py3-none-any.whl → 1.1.0__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.
- langchain_arcade/_utilities.py +4 -7
- langchain_arcade/manager.py +52 -17
- {langchain_arcade-0.1.2.dist-info → langchain_arcade-1.1.0.dist-info}/LICENSE +1 -1
- {langchain_arcade-0.1.2.dist-info → langchain_arcade-1.1.0.dist-info}/METADATA +12 -15
- langchain_arcade-1.1.0.dist-info/RECORD +8 -0
- langchain_arcade-0.1.2.dist-info/RECORD +0 -8
- {langchain_arcade-0.1.2.dist-info → langchain_arcade-1.1.0.dist-info}/WHEEL +0 -0
langchain_arcade/_utilities.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, Callable
|
|
2
2
|
|
|
3
3
|
from arcadepy import NOT_GIVEN, Arcade
|
|
4
|
-
from arcadepy.types
|
|
4
|
+
from arcadepy.types import ToolDefinition
|
|
5
5
|
from langchain_core.runnables import RunnableConfig
|
|
6
6
|
from langchain_core.tools import StructuredTool
|
|
7
7
|
from pydantic import BaseModel, Field, create_model
|
|
@@ -50,7 +50,7 @@ def tool_definition_to_pydantic_model(tool_def: ToolDefinition) -> type[BaseMode
|
|
|
50
50
|
"""
|
|
51
51
|
try:
|
|
52
52
|
fields: dict[str, Any] = {}
|
|
53
|
-
for param in tool_def.
|
|
53
|
+
for param in tool_def.input.parameters or []:
|
|
54
54
|
param_type = get_python_type(param.value_schema.val_type)
|
|
55
55
|
if param_type == list and param.value_schema.inner_val_type: # noqa: E721
|
|
56
56
|
inner_type: type[Any] = get_python_type(param.value_schema.inner_val_type)
|
|
@@ -116,10 +116,7 @@ def create_tool_function(
|
|
|
116
116
|
# Authorize the user for the tool
|
|
117
117
|
auth_response = client.tools.authorize(tool_name=tool_name, user_id=user_id)
|
|
118
118
|
if auth_response.status != "completed":
|
|
119
|
-
auth_message =
|
|
120
|
-
"Please use the following link to authorize: "
|
|
121
|
-
f"{auth_response.authorization_url}"
|
|
122
|
-
)
|
|
119
|
+
auth_message = f"Please use the following link to authorize: {auth_response.url}"
|
|
123
120
|
if langgraph:
|
|
124
121
|
raise NodeInterrupt(auth_message)
|
|
125
122
|
return {"error": auth_message}
|
|
@@ -127,7 +124,7 @@ def create_tool_function(
|
|
|
127
124
|
# Execute the tool with provided inputs
|
|
128
125
|
execute_response = client.tools.execute(
|
|
129
126
|
tool_name=tool_name,
|
|
130
|
-
|
|
127
|
+
input=kwargs,
|
|
131
128
|
user_id=user_id if user_id is not None else NOT_GIVEN,
|
|
132
129
|
)
|
|
133
130
|
|
langchain_arcade/manager.py
CHANGED
|
@@ -3,7 +3,8 @@ from collections.abc import Iterator
|
|
|
3
3
|
from typing import Any, Optional
|
|
4
4
|
|
|
5
5
|
from arcadepy import Arcade
|
|
6
|
-
from arcadepy.types
|
|
6
|
+
from arcadepy.types import ToolDefinition
|
|
7
|
+
from arcadepy.types.shared import AuthorizationResponse
|
|
7
8
|
from langchain_core.tools import StructuredTool
|
|
8
9
|
|
|
9
10
|
from langchain_arcade._utilities import (
|
|
@@ -40,10 +41,16 @@ class ArcadeToolManager:
|
|
|
40
41
|
|
|
41
42
|
Args:
|
|
42
43
|
client: Optional Arcade client instance.
|
|
44
|
+
**kwargs: Additional keyword arguments to pass to the Arcade client.
|
|
43
45
|
"""
|
|
44
46
|
if not client:
|
|
45
|
-
api_key = kwargs.get("api_key", os.getenv("ARCADE_API_KEY"
|
|
46
|
-
|
|
47
|
+
api_key = kwargs.get("api_key", os.getenv("ARCADE_API_KEY"))
|
|
48
|
+
base_url = kwargs.get("base_url", os.getenv("ARCADE_BASE_URL"))
|
|
49
|
+
arcade_kwargs = {"api_key": api_key, **kwargs}
|
|
50
|
+
if base_url:
|
|
51
|
+
arcade_kwargs["base_url"] = base_url
|
|
52
|
+
|
|
53
|
+
client = Arcade(**arcade_kwargs) # type: ignore[arg-type]
|
|
47
54
|
self.client = client
|
|
48
55
|
self._tools: dict[str, ToolDefinition] = {}
|
|
49
56
|
|
|
@@ -84,13 +91,17 @@ class ArcadeToolManager:
|
|
|
84
91
|
self,
|
|
85
92
|
tools: Optional[list[str]] = None,
|
|
86
93
|
toolkits: Optional[list[str]] = None,
|
|
87
|
-
langgraph: bool =
|
|
94
|
+
langgraph: bool = True,
|
|
88
95
|
) -> list[StructuredTool]:
|
|
89
96
|
"""Return the tools in the manager as LangChain StructuredTool objects.
|
|
90
97
|
|
|
91
98
|
Note: if tools/toolkits are provided, the manager will update it's
|
|
92
99
|
internal tools using a dictionary update by tool name.
|
|
93
100
|
|
|
101
|
+
If langgraph is True, the tools will be wrapped with LangGraph-specific
|
|
102
|
+
behavior such as NodeInterrupts for auth.
|
|
103
|
+
Note: Changed in 1.0.0 to default to True.
|
|
104
|
+
|
|
94
105
|
Example:
|
|
95
106
|
>>> manager = ArcadeToolManager(api_key="...")
|
|
96
107
|
>>>
|
|
@@ -143,7 +154,20 @@ class ArcadeToolManager:
|
|
|
143
154
|
>>> manager.init_tools(toolkits=["Search"])
|
|
144
155
|
>>> manager.is_authorized("auth_123")
|
|
145
156
|
"""
|
|
146
|
-
return self.client.auth.status(
|
|
157
|
+
return self.client.auth.status(id=authorization_id).status == "completed"
|
|
158
|
+
|
|
159
|
+
def wait_for_auth(self, authorization_id: str) -> AuthorizationResponse:
|
|
160
|
+
"""Wait for a tool authorization to complete.
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> manager = ArcadeToolManager(api_key="...")
|
|
164
|
+
>>> manager.init_tools(toolkits=["Google.ListEmails"])
|
|
165
|
+
>>> response = manager.authorize("Google.ListEmails", "user_123")
|
|
166
|
+
>>> manager.wait_for_auth(response)
|
|
167
|
+
>>> # or
|
|
168
|
+
>>> manager.wait_for_auth(response.id)
|
|
169
|
+
"""
|
|
170
|
+
return self.client.auth.wait_for_completion(authorization_id)
|
|
147
171
|
|
|
148
172
|
def requires_auth(self, tool_name: str) -> bool:
|
|
149
173
|
"""Check if a tool requires authorization."""
|
|
@@ -162,22 +186,33 @@ class ArcadeToolManager:
|
|
|
162
186
|
def _retrieve_tool_definitions(
|
|
163
187
|
self, tools: Optional[list[str]] = None, toolkits: Optional[list[str]] = None
|
|
164
188
|
) -> dict[str, ToolDefinition]:
|
|
189
|
+
"""Retrieve tool definitions from the Arcade client, accounting for pagination."""
|
|
165
190
|
all_tools: list[ToolDefinition] = []
|
|
166
|
-
if tools is not None or toolkits is not None:
|
|
167
|
-
if tools:
|
|
168
|
-
single_tools = [self.client.tools.get(tool_id=tool_id) for tool_id in tools]
|
|
169
|
-
all_tools.extend(single_tools)
|
|
170
|
-
if toolkits:
|
|
171
|
-
for tk in toolkits:
|
|
172
|
-
all_tools.extend(self.client.tools.list(toolkit=tk))
|
|
173
|
-
else:
|
|
174
|
-
# retrieve all tools
|
|
175
|
-
page_iterator = self.client.tools.list()
|
|
176
|
-
all_tools.extend(page_iterator)
|
|
177
191
|
|
|
192
|
+
# First, gather single tools if the user specifically requested them.
|
|
193
|
+
if tools:
|
|
194
|
+
for tool_id in tools:
|
|
195
|
+
# ToolsResource.get(...) returns a single ToolDefinition.
|
|
196
|
+
single_tool = self.client.tools.get(name=tool_id)
|
|
197
|
+
all_tools.append(single_tool)
|
|
198
|
+
|
|
199
|
+
# Next, gather tool definitions from any requested toolkits.
|
|
200
|
+
if toolkits:
|
|
201
|
+
for tk in toolkits:
|
|
202
|
+
# tools.list(...) returns a paginated response (SyncOffsetPage),
|
|
203
|
+
# which has an __iter__ method that automatically iterates over all pages.
|
|
204
|
+
paginated_tools = self.client.tools.list(toolkit=tk)
|
|
205
|
+
all_tools.extend(paginated_tools)
|
|
206
|
+
|
|
207
|
+
# If no specific tools or toolkits were requested, retrieve *all* tools.
|
|
208
|
+
if not tools and not toolkits:
|
|
209
|
+
paginated_all_tools = self.client.tools.list()
|
|
210
|
+
all_tools.extend(paginated_all_tools)
|
|
211
|
+
# Build a dictionary that maps the "full_tool_name" to the tool definition.
|
|
178
212
|
tool_definitions: dict[str, ToolDefinition] = {}
|
|
179
|
-
|
|
180
213
|
for tool in all_tools:
|
|
214
|
+
# For items returned by .list(), the 'toolkit' and 'name' attributes
|
|
215
|
+
# should be present as plain fields on the object. (No need to do toolkit.name)
|
|
181
216
|
full_tool_name = f"{tool.toolkit.name}_{tool.name}"
|
|
182
217
|
tool_definitions[full_tool_name] = tool
|
|
183
218
|
|
|
@@ -1,33 +1,31 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langchain-arcade
|
|
3
|
-
Version:
|
|
4
|
-
Summary: An integration package connecting Arcade
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: An integration package connecting Arcade and Langchain/LangGraph
|
|
5
5
|
Home-page: https://github.com/arcadeai/arcade-ai/tree/main/contrib/langchain
|
|
6
6
|
License: MIT
|
|
7
|
-
Author: Arcade
|
|
8
|
-
Author-email: dev@arcade
|
|
7
|
+
Author: Arcade
|
|
8
|
+
Author-email: dev@arcade.dev
|
|
9
9
|
Requires-Python: >=3.10,<3.13
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist: langchain-core (>=0.3.0,<0.4.0)
|
|
18
|
-
Requires-Dist: langgraph (>=0.2.32,<0.3.0) ; extra == "langgraph"
|
|
15
|
+
Requires-Dist: arcadepy (==1.1.*)
|
|
16
|
+
Requires-Dist: langgraph (>=0.2.67,<0.3.0)
|
|
19
17
|
Project-URL: Repository, https://github.com/arcadeai/arcade-ai/tree/main/contrib/langchain
|
|
20
18
|
Description-Content-Type: text/markdown
|
|
21
19
|
|
|
22
20
|
<h3 align="center">
|
|
23
21
|
<a name="readme-top"></a>
|
|
24
22
|
<img
|
|
25
|
-
src="https://docs.arcade
|
|
23
|
+
src="https://docs.arcade.dev/images/logo/arcade-logo.png"
|
|
26
24
|
>
|
|
27
25
|
</h3>
|
|
28
26
|
<div align="center">
|
|
29
|
-
<h3>
|
|
30
|
-
<a href="https://github.com/arcadeai/arcade
|
|
27
|
+
<h3>Arcade Langchain Integration</h3>
|
|
28
|
+
<a href="https://github.com/arcadeai/langchain-arcade/blob/main/LICENSE">
|
|
31
29
|
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License">
|
|
32
30
|
</a>
|
|
33
31
|
<a href="https://pepy.tech/project/langchain-arcade">
|
|
@@ -37,16 +35,15 @@ Description-Content-Type: text/markdown
|
|
|
37
35
|
</div>
|
|
38
36
|
|
|
39
37
|
<p align="center">
|
|
40
|
-
<a href="https://docs.arcade
|
|
41
|
-
<a href="https://docs.arcade
|
|
42
|
-
<a href="https://github.com/ArcadeAI/cookbook" target="_blank">Cookbook</a> •
|
|
38
|
+
<a href="https://docs.arcade.dev" target="_blank">Arcade Documentation</a> •
|
|
39
|
+
<a href="https://docs.arcade.dev/toolkits" target="_blank">Toolkits</a> •
|
|
43
40
|
<a href="https://github.com/ArcadeAI/arcade-py" target="_blank">Python Client</a> •
|
|
44
41
|
<a href="https://github.com/ArcadeAI/arcade-js" target="_blank">JavaScript Client</a>
|
|
45
42
|
</p>
|
|
46
43
|
|
|
47
44
|
## Overview
|
|
48
45
|
|
|
49
|
-
`langchain-arcade` allows you to use Arcade
|
|
46
|
+
`langchain-arcade` allows you to use Arcade tools in your LangChain and LangGraph applications.
|
|
50
47
|
|
|
51
48
|
## Installation
|
|
52
49
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
langchain_arcade/__init__.py,sha256=nYAKEQBNNacNjGU6r_UY3lpkNzurGdujh2AsmdOky78,72
|
|
2
|
+
langchain_arcade/_utilities.py,sha256=LvT3kYS1urBftixyzOlQbzYsBQC5zn8_VE9xkIxCfRY,5946
|
|
3
|
+
langchain_arcade/manager.py,sha256=hltA3Tmv4ak_aRvkvu5DXv2nXbYP63Wm0V6YkkoR_vk,8222
|
|
4
|
+
langchain_arcade/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
langchain_arcade-1.1.0.dist-info/LICENSE,sha256=f4Q0XUZJ2MqZBO1XsqqHhuZfSs2ar1cZEJ45150zERo,1067
|
|
6
|
+
langchain_arcade-1.1.0.dist-info/METADATA,sha256=ZHojv1k2g_vKrt1IpTG66U8Rp_Tls3py8uiS7SmpeSg,1914
|
|
7
|
+
langchain_arcade-1.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
8
|
+
langchain_arcade-1.1.0.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
langchain_arcade/__init__.py,sha256=nYAKEQBNNacNjGU6r_UY3lpkNzurGdujh2AsmdOky78,72
|
|
2
|
-
langchain_arcade/_utilities.py,sha256=G6IEYfhSh4dPa7tT94qHMP1QmgP2xyTLibwtMXYRHy4,6032
|
|
3
|
-
langchain_arcade/manager.py,sha256=2mSwGu89a91KH0qDk9KVcslKapEDmcUHIzpLuy2Xxhg,6371
|
|
4
|
-
langchain_arcade/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
langchain_arcade-0.1.2.dist-info/LICENSE,sha256=108KqUBZubw2RlcTUyNL3IdivNNLKjXoONGFEmzoaeo,1067
|
|
6
|
-
langchain_arcade-0.1.2.dist-info/METADATA,sha256=LZUlUCqzgW9j93qU2BrkA4MoKcwwamoZ9cTY7fQHHEg,2103
|
|
7
|
-
langchain_arcade-0.1.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
8
|
-
langchain_arcade-0.1.2.dist-info/RECORD,,
|
|
File without changes
|