langchain-arcade 1.1.0__py3-none-any.whl → 1.3.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/__init__.py +6 -2
- langchain_arcade/_utilities.py +132 -17
- langchain_arcade/manager.py +742 -129
- langchain_arcade-1.3.0.dist-info/METADATA +192 -0
- langchain_arcade-1.3.0.dist-info/RECORD +8 -0
- langchain_arcade-1.1.0.dist-info/METADATA +0 -57
- langchain_arcade-1.1.0.dist-info/RECORD +0 -8
- {langchain_arcade-1.1.0.dist-info → langchain_arcade-1.3.0.dist-info}/LICENSE +0 -0
- {langchain_arcade-1.1.0.dist-info → langchain_arcade-1.3.0.dist-info}/WHEEL +0 -0
langchain_arcade/__init__.py
CHANGED
langchain_arcade/_utilities.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Any, Callable
|
|
1
|
+
from typing import Any, Callable, Union
|
|
2
2
|
|
|
3
|
-
from arcadepy import NOT_GIVEN, Arcade
|
|
4
|
-
from arcadepy.types import ToolDefinition
|
|
3
|
+
from arcadepy import NOT_GIVEN, Arcade, AsyncArcade
|
|
4
|
+
from arcadepy.types import ExecuteToolResponse, 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
|
|
@@ -68,6 +68,51 @@ def tool_definition_to_pydantic_model(tool_def: ToolDefinition) -> type[BaseMode
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
def process_tool_execution_response(
|
|
72
|
+
execute_response: ExecuteToolResponse, tool_name: str, langgraph: bool
|
|
73
|
+
) -> Any:
|
|
74
|
+
"""Process the response from tool execution and handle errors appropriately.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
execute_response: The response from tool execution
|
|
78
|
+
tool_name: The name of the tool that was executed
|
|
79
|
+
langgraph: Whether LangGraph-specific behavior is enabled
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The output value on success, or error details on failure
|
|
83
|
+
"""
|
|
84
|
+
if execute_response.success and execute_response.output is not None:
|
|
85
|
+
return execute_response.output.value
|
|
86
|
+
|
|
87
|
+
# Extract detailed error information
|
|
88
|
+
error_details = {
|
|
89
|
+
"error": "Unknown error occurred",
|
|
90
|
+
"tool": tool_name,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if execute_response.output is not None and execute_response.output.error is not None:
|
|
94
|
+
error = execute_response.output.error
|
|
95
|
+
error_message = str(error.message) if hasattr(error, "message") else "Unknown error"
|
|
96
|
+
error_details["error"] = error_message
|
|
97
|
+
|
|
98
|
+
# Add all non-None optional error fields to the details
|
|
99
|
+
if (
|
|
100
|
+
hasattr(error, "additional_prompt_content")
|
|
101
|
+
and error.additional_prompt_content is not None
|
|
102
|
+
):
|
|
103
|
+
error_details["additional_prompt_content"] = error.additional_prompt_content
|
|
104
|
+
if hasattr(error, "can_retry") and error.can_retry is not None:
|
|
105
|
+
error_details["can_retry"] = str(error.can_retry)
|
|
106
|
+
if hasattr(error, "developer_message") and error.developer_message is not None:
|
|
107
|
+
error_details["developer_message"] = str(error.developer_message)
|
|
108
|
+
if hasattr(error, "retry_after_ms") and error.retry_after_ms is not None:
|
|
109
|
+
error_details["retry_after_ms"] = str(error.retry_after_ms)
|
|
110
|
+
|
|
111
|
+
if langgraph:
|
|
112
|
+
raise NodeInterrupt(error_details)
|
|
113
|
+
return error_details
|
|
114
|
+
|
|
115
|
+
|
|
71
116
|
def create_tool_function(
|
|
72
117
|
client: Arcade,
|
|
73
118
|
tool_name: str,
|
|
@@ -128,18 +173,13 @@ def create_tool_function(
|
|
|
128
173
|
user_id=user_id if user_id is not None else NOT_GIVEN,
|
|
129
174
|
)
|
|
130
175
|
|
|
131
|
-
|
|
132
|
-
return execute_response.output.value # type: ignore[union-attr]
|
|
133
|
-
error_message = str(execute_response.output.error) # type: ignore[union-attr]
|
|
134
|
-
if langgraph:
|
|
135
|
-
raise NodeInterrupt(error_message)
|
|
136
|
-
return {"error": error_message}
|
|
176
|
+
return process_tool_execution_response(execute_response, tool_name, langgraph)
|
|
137
177
|
|
|
138
178
|
return tool_function
|
|
139
179
|
|
|
140
180
|
|
|
141
181
|
def wrap_arcade_tool(
|
|
142
|
-
client: Arcade,
|
|
182
|
+
client: Union[Arcade, AsyncArcade],
|
|
143
183
|
tool_name: str,
|
|
144
184
|
tool_def: ToolDefinition,
|
|
145
185
|
langgraph: bool = False,
|
|
@@ -161,13 +201,23 @@ def wrap_arcade_tool(
|
|
|
161
201
|
args_schema = tool_definition_to_pydantic_model(tool_def)
|
|
162
202
|
|
|
163
203
|
# Create the action function
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
204
|
+
if isinstance(client, Arcade):
|
|
205
|
+
action_func = create_tool_function(
|
|
206
|
+
client=client,
|
|
207
|
+
tool_name=tool_name,
|
|
208
|
+
tool_def=tool_def,
|
|
209
|
+
args_schema=args_schema,
|
|
210
|
+
langgraph=langgraph,
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
# Use async tool function for AsyncArcade client
|
|
214
|
+
action_func = create_async_tool_function(
|
|
215
|
+
client=client,
|
|
216
|
+
tool_name=tool_name,
|
|
217
|
+
tool_def=tool_def,
|
|
218
|
+
args_schema=args_schema,
|
|
219
|
+
langgraph=langgraph,
|
|
220
|
+
)
|
|
171
221
|
|
|
172
222
|
# Create the StructuredTool instance
|
|
173
223
|
return StructuredTool.from_function(
|
|
@@ -177,3 +227,68 @@ def wrap_arcade_tool(
|
|
|
177
227
|
args_schema=args_schema,
|
|
178
228
|
inject_kwargs={"user_id"},
|
|
179
229
|
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def create_async_tool_function(
|
|
233
|
+
client: AsyncArcade,
|
|
234
|
+
tool_name: str,
|
|
235
|
+
tool_def: ToolDefinition,
|
|
236
|
+
args_schema: type[BaseModel],
|
|
237
|
+
langgraph: bool = False,
|
|
238
|
+
) -> Callable:
|
|
239
|
+
"""Create an async callable function to execute an Arcade tool.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
client: The AsyncArcade client instance.
|
|
243
|
+
tool_name: The name of the tool to wrap.
|
|
244
|
+
tool_def: The ToolDefinition of the tool to wrap.
|
|
245
|
+
args_schema: The Pydantic model representing the tool's arguments.
|
|
246
|
+
langgraph: Whether to enable LangGraph-specific behavior.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
An async callable function that executes the tool.
|
|
250
|
+
"""
|
|
251
|
+
if langgraph and not LANGGRAPH_ENABLED:
|
|
252
|
+
raise ImportError("LangGraph is not installed. Please install it to use this feature.")
|
|
253
|
+
|
|
254
|
+
requires_authorization = (
|
|
255
|
+
tool_def.requirements is not None and tool_def.requirements.authorization is not None
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
async def tool_function(config: RunnableConfig, **kwargs: Any) -> Any:
|
|
259
|
+
"""Run the Arcade tool with the given parameters.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
config: RunnableConfig containing execution context.
|
|
263
|
+
**kwargs: Tool input arguments.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
The output from the tool execution.
|
|
267
|
+
"""
|
|
268
|
+
user_id = config.get("configurable", {}).get("user_id") if config else None
|
|
269
|
+
|
|
270
|
+
if requires_authorization:
|
|
271
|
+
if user_id is None:
|
|
272
|
+
error_message = f"user_id is required to run {tool_name}"
|
|
273
|
+
if langgraph:
|
|
274
|
+
raise NodeInterrupt(error_message)
|
|
275
|
+
return {"error": error_message}
|
|
276
|
+
|
|
277
|
+
# Authorize the user for the tool
|
|
278
|
+
auth_response = await client.tools.authorize(tool_name=tool_name, user_id=user_id)
|
|
279
|
+
if auth_response.status != "completed":
|
|
280
|
+
auth_message = f"Please use the following link to authorize: {auth_response.url}"
|
|
281
|
+
if langgraph:
|
|
282
|
+
raise NodeInterrupt(auth_message)
|
|
283
|
+
return {"error": auth_message}
|
|
284
|
+
|
|
285
|
+
# Execute the tool with provided inputs
|
|
286
|
+
execute_response = await client.tools.execute(
|
|
287
|
+
tool_name=tool_name,
|
|
288
|
+
input=kwargs,
|
|
289
|
+
user_id=user_id if user_id is not None else NOT_GIVEN,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return process_tool_execution_response(execute_response, tool_name, langgraph)
|
|
293
|
+
|
|
294
|
+
return tool_function
|