Skip to content

Commit b22d2eb

Browse files
committed
fix: Base toolbox sync & async tools to toolbox core counterparts
1 parent 9eccd3a commit b22d2eb

File tree

4 files changed

+38
-106
lines changed

4 files changed

+38
-106
lines changed

packages/toolbox-langchain/src/toolbox_langchain/async_client.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717

1818
from aiohttp import ClientSession
1919

20-
from .tools import AsyncToolboxTool
21-
20+
from .async_tools import AsyncToolboxTool
2221
from toolbox_core.client import ToolboxClient as ToolboxCoreClient
2322

2423

packages/toolbox-langchain/src/toolbox_langchain/async_tools.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,12 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from copy import deepcopy
16-
from typing import Any, Callable, TypeVar, Union
17-
from warnings import warn
15+
from typing import Any, Callable, Union
1816

1917
from langchain_core.tools import BaseTool
2018
from toolbox_core.tool import ToolboxTool as ToolboxCoreTool
2119

2220

23-
T = TypeVar("T")
24-
2521

2622
# This class is an internal implementation detail and is not exposed to the
2723
# end-user. It should not be used directly by external code. Changes to this
@@ -40,14 +36,7 @@ def __init__(
4036
Initializes an AsyncToolboxTool instance.
4137
4238
Args:
43-
name: The name of the tool.
44-
schema: The tool schema.
45-
url: The base URL of the Toolbox service.
46-
session: The HTTP client session.
47-
auth_token_getters: A mapping of authentication source names to
48-
functions that retrieve ID tokens.
49-
bound_params: A mapping of parameter names to their bound
50-
values.
39+
core_tool: The underlying core async ToolboxTool instance.
5140
"""
5241

5342
self.__core_tool = core_tool
@@ -88,7 +77,7 @@ def add_auth_token_getters(
8877
8978
Returns:
9079
A new AsyncToolboxTool instance that is a deep copy of the current
91-
instance, with added auth tokens.
80+
instance, with added auth token getters.
9281
9382
Raises:
9483
ValueError: If any of the provided auth parameters is already

packages/toolbox-langchain/src/toolbox_langchain/client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ async def aload_tool(
9595
return await coro
9696

9797
# Otherwise, run in the background thread.
98-
core_tool = await asyncio.wrap_future(
98+
core_sync_tool = await asyncio.wrap_future(
9999
asyncio.run_coroutine_threadsafe(coro, self.__core_sync_client._ToolboxSyncClient__loop)
100100
)
101101

102-
return ToolboxTool(core_tool=core_tool)
102+
return ToolboxTool(core_sync_tool=core_sync_tool)
103103

104104
async def aload_toolset(
105105
self,
@@ -170,13 +170,13 @@ async def aload_toolset(
170170
return await coro
171171

172172
# Otherwise, run in the background thread.
173-
core_tools = await asyncio.wrap_future(
173+
core_sync_tools = await asyncio.wrap_future(
174174
asyncio.run_coroutine_threadsafe(coro, self.__core_sync_client._ToolboxSyncClient__loop)
175175
)
176176

177177
tools = []
178-
for core_tool in core_tools:
179-
tools.append(ToolboxTool(core_tool=core_tool))
178+
for core_sync_tool in core_sync_tools:
179+
tools.append(ToolboxTool(core_sync_tool=core_sync_tool))
180180
return tools
181181

182182
def load_tool(
@@ -228,12 +228,12 @@ def load_tool(
228228
)
229229
auth_token_getters = auth_tokens
230230

231-
core_tool = self.__core_sync_client.load_tool(
231+
core_sync_tool = self.__core_sync_client.load_tool(
232232
name=tool_name,
233233
auth_token_getters=auth_token_getters,
234234
bound_params=bound_params
235235
)
236-
return ToolboxTool(core_tool=core_tool)
236+
return ToolboxTool(core_sync_tool=core_sync_tool)
237237

238238
def load_toolset(
239239
self,
@@ -292,14 +292,14 @@ def load_toolset(
292292
)
293293
auth_token_getters = auth_tokens
294294

295-
core_tools = self.__core_sync_client.load_toolset(
295+
core_sync_tools = self.__core_sync_client.load_toolset(
296296
name=toolset_name,
297297
auth_token_getters=auth_token_getters,
298298
bound_params=bound_params,
299299
strict=strict
300300
)
301301

302302
tools = []
303-
for core_tool in core_tools:
304-
tools.append(ToolboxTool(core_tool=core_tool))
303+
for core_sync_tool in core_sync_tools:
304+
tools.append(ToolboxTool(core_sync_tool=core_sync_tool))
305305
return tools

packages/toolbox-langchain/src/toolbox_langchain/tools.py

Lines changed: 24 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@
1313
# limitations under the License.
1414

1515
import asyncio
16-
from asyncio import AbstractEventLoop
17-
from threading import Thread
18-
from typing import Any, Awaitable, Callable, TypeVar, Union
16+
from typing import Any, Callable, Union
1917

2018
from langchain_core.tools import BaseTool
19+
from toolbox_core.sync_tool import ToolboxSyncTool as ToolboxCoreSyncTool
2120

22-
from .async_tools import AsyncToolboxTool
23-
24-
T = TypeVar("T")
2521

2622

2723
class ToolboxTool(BaseTool):
@@ -32,56 +28,37 @@ class ToolboxTool(BaseTool):
3228

3329
def __init__(
3430
self,
35-
async_tool: AsyncToolboxTool,
36-
loop: AbstractEventLoop,
37-
thread: Thread,
31+
core_sync_tool: ToolboxCoreSyncTool,
3832
) -> None:
3933
"""
4034
Initializes a ToolboxTool instance.
4135
4236
Args:
43-
async_tool: The underlying AsyncToolboxTool instance.
44-
loop: The event loop used to run asynchronous tasks.
45-
thread: The thread to run blocking operations in.
37+
core_sync_tool: The underlying core sync ToolboxTool instance.
4638
"""
4739

48-
# Due to how pydantic works, we must initialize the underlying
49-
# BaseTool class before assigning values to member variables.
40+
self.__core_sync_tool = core_sync_tool
5041
super().__init__(
51-
name=async_tool.name,
52-
description=async_tool.description,
53-
args_schema=async_tool.args_schema,
42+
name=self.__core_sync_tool.__name__,
43+
description=self.__core_sync_tool.__doc__,
44+
args_schema=self.__core_sync_tool._ToolboxSyncTool__pydantic_model,
5445
)
5546

56-
self.__async_tool = async_tool
57-
self.__loop = loop
58-
self.__thread = thread
59-
60-
def __run_as_sync(self, coro: Awaitable[T]) -> T:
61-
"""Run an async coroutine synchronously"""
62-
if not self.__loop:
63-
raise Exception(
64-
"Cannot call synchronous methods before the background loop is initialized."
65-
)
66-
return asyncio.run_coroutine_threadsafe(coro, self.__loop).result()
47+
def _run(self, **kwargs: Any) -> dict[str, Any]:
48+
return self.__core_sync_tool(**kwargs)
6749

68-
async def __run_as_async(self, coro: Awaitable[T]) -> T:
69-
"""Run an async coroutine asynchronously"""
50+
async def _arun(self, **kwargs: Any) -> dict[str, Any]:
51+
coro = self.__core_sync_tool._ToolboxSyncTool__async_tool(**kwargs)
7052

7153
# If a loop has not been provided, attempt to run in current thread.
72-
if not self.__loop:
54+
if not self.__core_sync_client._ToolboxSyncClient__loop:
7355
return await coro
7456

7557
# Otherwise, run in the background thread.
76-
return await asyncio.wrap_future(
77-
asyncio.run_coroutine_threadsafe(coro, self.__loop)
58+
await asyncio.wrap_future(
59+
asyncio.run_coroutine_threadsafe(coro, self.__core_sync_client._ToolboxSyncTool__loop)
7860
)
7961

80-
def _run(self, **kwargs: Any) -> dict[str, Any]:
81-
return self.__run_as_sync(self.__async_tool._arun(**kwargs))
82-
83-
async def _arun(self, **kwargs: Any) -> dict[str, Any]:
84-
return await self.__run_as_async(self.__async_tool._arun(**kwargs))
8562

8663
def add_auth_token_getters(
8764
self, auth_token_getters: dict[str, Callable[[], str]], strict: bool = True
@@ -93,27 +70,21 @@ def add_auth_token_getters(
9370
Args:
9471
auth_token_getters: A dictionary of authentication source names to
9572
the functions that return corresponding ID token.
96-
strict: If True, a ValueError is raised if any of the provided auth
97-
parameters is already bound. If False, only a warning is issued.
9873
9974
Returns:
10075
A new ToolboxTool instance that is a deep copy of the current
101-
instance, with added auth tokens.
76+
instance, with added auth token getters.
10277
10378
Raises:
10479
ValueError: If any of the provided auth parameters is already
10580
registered.
106-
ValueError: If any of the provided auth parameters is already bound
107-
and strict is True.
10881
"""
109-
return ToolboxTool(
110-
self.__async_tool.add_auth_token_getters(auth_token_getters, strict),
111-
self.__loop,
112-
self.__thread,
113-
)
82+
new_core_sync_tool = self.__core_sync_tool.add_auth_token_getters(auth_token_getters)
83+
return ToolboxTool(core_sync_tool=new_core_sync_tool)
84+
11485

11586
def add_auth_token_getter(
116-
self, auth_source: str, get_id_token: Callable[[], str], strict: bool = True
87+
self, auth_source: str, get_id_token: Callable[[], str]
11788
) -> "ToolboxTool":
11889
"""
11990
Registers a function to retrieve an ID token for a given authentication
@@ -122,28 +93,19 @@ def add_auth_token_getter(
12293
Args:
12394
auth_source: The name of the authentication source.
12495
get_id_token: A function that returns the ID token.
125-
strict: If True, a ValueError is raised if the provided auth
126-
parameter is already bound. If False, only a warning is issued.
12796
12897
Returns:
12998
A new ToolboxTool instance that is a deep copy of the current
13099
instance, with added auth token.
131100
132101
Raises:
133102
ValueError: If the provided auth parameter is already registered.
134-
ValueError: If the provided auth parameter is already bound and
135-
strict is True.
136103
"""
137-
return ToolboxTool(
138-
self.__async_tool.add_auth_token_getter(auth_source, get_id_token, strict),
139-
self.__loop,
140-
self.__thread,
141-
)
104+
return self.add_auth_token_getters({auth_source: get_id_token})
142105

143106
def bind_params(
144107
self,
145108
bound_params: dict[str, Union[Any, Callable[[], Any]]],
146-
strict: bool = True,
147109
) -> "ToolboxTool":
148110
"""
149111
Registers values or functions to retrieve the value for the
@@ -152,25 +114,16 @@ def bind_params(
152114
Args:
153115
bound_params: A dictionary of the bound parameter name to the
154116
value or function of the bound value.
155-
strict: If True, a ValueError is raised if any of the provided bound
156-
params is not defined in the tool's schema, or requires
157-
authentication. If False, only a warning is issued.
158117
159118
Returns:
160119
A new ToolboxTool instance that is a deep copy of the current
161120
instance, with added bound params.
162121
163122
Raises:
164123
ValueError: If any of the provided bound params is already bound.
165-
ValueError: if any of the provided bound params is not defined in
166-
the tool's schema, or require authentication, and strict is
167-
True.
168124
"""
169-
return ToolboxTool(
170-
self.__async_tool.bind_params(bound_params, strict),
171-
self.__loop,
172-
self.__thread,
173-
)
125+
new_core_sync_tool = self.__core_sync_tool.bind_params(bound_params)
126+
return ToolboxTool(core_sync_tool=new_core_sync_tool)
174127

175128
def bind_param(
176129
self,
@@ -186,21 +139,12 @@ def bind_param(
186139
param_name: The name of the bound parameter.
187140
param_value: The value of the bound parameter, or a callable that
188141
returns the value.
189-
strict: If True, a ValueError is raised if the provided bound
190-
param is not defined in the tool's schema, or requires
191-
authentication. If False, only a warning is issued.
192142
193143
Returns:
194144
A new ToolboxTool instance that is a deep copy of the current
195145
instance, with added bound param.
196146
197147
Raises:
198148
ValueError: If the provided bound param is already bound.
199-
ValueError: if the provided bound param is not defined in the tool's
200-
schema, or requires authentication, and strict is True.
201149
"""
202-
return ToolboxTool(
203-
self.__async_tool.bind_param(param_name, param_value, strict),
204-
self.__loop,
205-
self.__thread,
206-
)
150+
return self.bind_params({param_name: param_value})

0 commit comments

Comments
 (0)