Skip to content

Commit d6753ea

Browse files
committed
fix: Base sync client
1 parent 6f58be6 commit d6753ea

File tree

2 files changed

+153
-126
lines changed

2 files changed

+153
-126
lines changed

packages/toolbox-core/src/toolbox_core/sync_client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ def load_toolset(
113113
name: str,
114114
auth_token_getters: dict[str, Callable[[], str]] = {},
115115
bound_params: Mapping[str, Union[Callable[[], Any], Any]] = {},
116+
strict: bool = False,
116117
) -> list[ToolboxSyncTool]:
117118
"""
118119
Synchronously fetches a toolset and loads all tools defined within it.
@@ -123,12 +124,17 @@ def load_toolset(
123124
callables that return the corresponding authentication token.
124125
bound_params: A mapping of parameter names to bind to specific values or
125126
callables that are called to produce values as needed.
127+
strict: If True, raises an error if *any* loaded tool instance fails
128+
to utilize at least one provided parameter or auth token (if any
129+
provided). If False (default), raises an error only if a
130+
user-provided parameter or auth token cannot be applied to *any*
131+
loaded tool across the set.
126132
127133
Returns:
128134
list[ToolboxSyncTool]: A list of callables, one for each tool defined
129135
in the toolset.
130136
"""
131-
coro = self.__async_client.load_toolset(name, auth_token_getters, bound_params)
137+
coro = self.__async_client.load_toolset(name, auth_token_getters, bound_params, strict)
132138

133139
if not self.__loop or not self.__thread:
134140
raise ValueError("Background loop or thread cannot be None.")

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

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

1515
import asyncio
16-
from threading import Thread
17-
from typing import Any, Awaitable, Callable, Optional, TypeVar, Union
16+
from warnings import warn
17+
from typing import Any, Callable, Optional, Union
1818

19-
from aiohttp import ClientSession
20-
21-
from .async_client import AsyncToolboxClient
2219
from .tools import ToolboxTool
20+
from toolbox_core.sync_client import ToolboxSyncClient as ToolboxCoreSyncClient
2321

24-
T = TypeVar("T")
2522

2623

2724
class ToolboxClient:
28-
__session: Optional[ClientSession] = None
29-
__loop: Optional[asyncio.AbstractEventLoop] = None
30-
__thread: Optional[Thread] = None
3125

3226
def __init__(
3327
self,
@@ -39,51 +33,7 @@ def __init__(
3933
Args:
4034
url: The base URL of the Toolbox service.
4135
"""
42-
43-
# Running a loop in a background thread allows us to support async
44-
# methods from non-async environments.
45-
if ToolboxClient.__loop is None:
46-
loop = asyncio.new_event_loop()
47-
thread = Thread(target=loop.run_forever, daemon=True)
48-
thread.start()
49-
ToolboxClient.__thread = thread
50-
ToolboxClient.__loop = loop
51-
52-
async def __start_session() -> None:
53-
54-
# Use a default session if none is provided. This leverages connection
55-
# pooling for better performance by reusing a single session throughout
56-
# the application's lifetime.
57-
if ToolboxClient.__session is None:
58-
ToolboxClient.__session = ClientSession()
59-
60-
coro = __start_session()
61-
62-
asyncio.run_coroutine_threadsafe(coro, ToolboxClient.__loop).result()
63-
64-
if not ToolboxClient.__session:
65-
raise ValueError("Session cannot be None.")
66-
self.__async_client = AsyncToolboxClient(url, ToolboxClient.__session)
67-
68-
def __run_as_sync(self, coro: Awaitable[T]) -> T:
69-
"""Run an async coroutine synchronously"""
70-
if not self.__loop:
71-
raise Exception(
72-
"Cannot call synchronous methods before the background loop is initialized."
73-
)
74-
return asyncio.run_coroutine_threadsafe(coro, self.__loop).result()
75-
76-
async def __run_as_async(self, coro: Awaitable[T]) -> T:
77-
"""Run an async coroutine asynchronously"""
78-
79-
# If a loop has not been provided, attempt to run in current thread.
80-
if not self.__loop:
81-
return await coro
82-
83-
# Otherwise, run in the background thread.
84-
return await asyncio.wrap_future(
85-
asyncio.run_coroutine_threadsafe(coro, self.__loop)
86-
)
36+
self.__core_sync_client = ToolboxCoreSyncClient(url=url)
8737

8838
async def aload_tool(
8939
self,
@@ -92,7 +42,6 @@ async def aload_tool(
9242
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
9343
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
9444
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
95-
strict: bool = True,
9645
) -> ToolboxTool:
9746
"""
9847
Loads the tool with the given tool name from the Toolbox service.
@@ -105,27 +54,42 @@ async def aload_tool(
10554
auth_headers: Deprecated. Use `auth_token_getters` instead.
10655
bound_params: An optional mapping of parameter names to their
10756
bound values.
108-
strict: If True, raises a ValueError if any of the given bound
109-
parameters are missing from the schema or require
110-
authentication. If False, only issues a warning.
11157
11258
Returns:
11359
A tool loaded from the Toolbox.
11460
"""
115-
async_tool = await self.__run_as_async(
116-
self.__async_client.aload_tool(
117-
tool_name,
118-
auth_token_getters,
119-
auth_tokens,
120-
auth_headers,
121-
bound_params,
122-
strict,
123-
)
61+
if auth_headers:
62+
if auth_token_getters:
63+
warn(
64+
"Both `auth_token_getters` and `auth_headers` are provided. `auth_headers` is deprecated, and `auth_token_getters` will be used.",
65+
DeprecationWarning,
66+
)
67+
else:
68+
warn(
69+
"Argument `auth_headers` is deprecated. Use `auth_token_getters` instead.",
70+
DeprecationWarning,
71+
)
72+
auth_token_getters = auth_headers
73+
74+
if auth_tokens:
75+
if auth_token_getters:
76+
warn(
77+
"Both `auth_token_getters` and `auth_tokens` are provided. `auth_tokens` is deprecated, and `auth_token_getters` will be used.",
78+
DeprecationWarning,
79+
)
80+
else:
81+
warn(
82+
"Argument `auth_tokens` is deprecated. Use `auth_token_getters` instead.",
83+
DeprecationWarning,
84+
)
85+
auth_token_getters = auth_tokens
86+
87+
core_tool = await self.__core_sync_client._ToolboxSyncClient__async_client.load_tool(
88+
name=tool_name,
89+
auth_token_getters=auth_token_getters,
90+
bound_params=bound_params
12491
)
125-
126-
if not self.__loop or not self.__thread:
127-
raise ValueError("Background loop or thread cannot be None.")
128-
return ToolboxTool(async_tool, self.__loop, self.__thread)
92+
return ToolboxTool(core_tool=core_tool)
12993

13094
async def aload_toolset(
13195
self,
@@ -134,7 +98,7 @@ async def aload_toolset(
13498
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
13599
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
136100
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
137-
strict: bool = True,
101+
strict: bool = False,
138102
) -> list[ToolboxTool]:
139103
"""
140104
Loads tools from the Toolbox service, optionally filtered by toolset
@@ -149,30 +113,51 @@ async def aload_toolset(
149113
auth_headers: Deprecated. Use `auth_token_getters` instead.
150114
bound_params: An optional mapping of parameter names to their
151115
bound values.
152-
strict: If True, raises a ValueError if any of the given bound
153-
parameters are missing from the schema or require
154-
authentication. If False, only issues a warning.
116+
strict: If True, raises an error if *any* loaded tool instance fails
117+
to utilize at least one provided parameter or auth token (if any
118+
provided). If False (default), raises an error only if a
119+
user-provided parameter or auth token cannot be applied to *any*
120+
loaded tool across the set.
155121
156122
Returns:
157123
A list of all tools loaded from the Toolbox.
158124
"""
159-
async_tools = await self.__run_as_async(
160-
self.__async_client.aload_toolset(
161-
toolset_name,
162-
auth_token_getters,
163-
auth_tokens,
164-
auth_headers,
165-
bound_params,
166-
strict,
167-
)
125+
if auth_headers:
126+
if auth_token_getters:
127+
warn(
128+
"Both `auth_token_getters` and `auth_headers` are provided. `auth_headers` is deprecated, and `auth_token_getters` will be used.",
129+
DeprecationWarning,
130+
)
131+
else:
132+
warn(
133+
"Argument `auth_headers` is deprecated. Use `auth_token_getters` instead.",
134+
DeprecationWarning,
135+
)
136+
auth_token_getters = auth_headers
137+
138+
if auth_tokens:
139+
if auth_token_getters:
140+
warn(
141+
"Both `auth_token_getters` and `auth_tokens` are provided. `auth_tokens` is deprecated, and `auth_token_getters` will be used.",
142+
DeprecationWarning,
143+
)
144+
else:
145+
warn(
146+
"Argument `auth_tokens` is deprecated. Use `auth_token_getters` instead.",
147+
DeprecationWarning,
148+
)
149+
auth_token_getters = auth_tokens
150+
151+
core_tools = await self.__core_sync_client._ToolboxSyncClient__async_client.load_toolset(
152+
name=toolset_name,
153+
auth_token_getters=auth_token_getters,
154+
bound_params=bound_params,
155+
strict=strict
168156
)
169157

170-
tools: list[ToolboxTool] = []
171-
172-
if not self.__loop or not self.__thread:
173-
raise ValueError("Background loop or thread cannot be None.")
174-
for async_tool in async_tools:
175-
tools.append(ToolboxTool(async_tool, self.__loop, self.__thread))
158+
tools = []
159+
for core_tool in core_tools:
160+
tools.append(ToolboxTool(core_tool_instance=core_tool))
176161
return tools
177162

178163
def load_tool(
@@ -182,7 +167,6 @@ def load_tool(
182167
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
183168
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
184169
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
185-
strict: bool = True,
186170
) -> ToolboxTool:
187171
"""
188172
Loads the tool with the given tool name from the Toolbox service.
@@ -195,27 +179,42 @@ def load_tool(
195179
auth_headers: Deprecated. Use `auth_token_getters` instead.
196180
bound_params: An optional mapping of parameter names to their
197181
bound values.
198-
strict: If True, raises a ValueError if any of the given bound
199-
parameters are missing from the schema or require
200-
authentication. If False, only issues a warning.
201182
202183
Returns:
203184
A tool loaded from the Toolbox.
204185
"""
205-
async_tool = self.__run_as_sync(
206-
self.__async_client.aload_tool(
207-
tool_name,
208-
auth_token_getters,
209-
auth_tokens,
210-
auth_headers,
211-
bound_params,
212-
strict,
213-
)
186+
if auth_headers:
187+
if auth_token_getters:
188+
warn(
189+
"Both `auth_token_getters` and `auth_headers` are provided. `auth_headers` is deprecated, and `auth_token_getters` will be used.",
190+
DeprecationWarning,
191+
)
192+
else:
193+
warn(
194+
"Argument `auth_headers` is deprecated. Use `auth_token_getters` instead.",
195+
DeprecationWarning,
196+
)
197+
auth_token_getters = auth_headers
198+
199+
if auth_tokens:
200+
if auth_token_getters:
201+
warn(
202+
"Both `auth_token_getters` and `auth_tokens` are provided. `auth_tokens` is deprecated, and `auth_token_getters` will be used.",
203+
DeprecationWarning,
204+
)
205+
else:
206+
warn(
207+
"Argument `auth_tokens` is deprecated. Use `auth_token_getters` instead.",
208+
DeprecationWarning,
209+
)
210+
auth_token_getters = auth_tokens
211+
212+
core_tool = self.__core_sync_client.load_tool(
213+
name=tool_name,
214+
auth_token_getters=auth_token_getters,
215+
bound_params=bound_params
214216
)
215-
216-
if not self.__loop or not self.__thread:
217-
raise ValueError("Background loop or thread cannot be None.")
218-
return ToolboxTool(async_tool, self.__loop, self.__thread)
217+
return ToolboxTool(core_tool=core_tool)
219218

220219
def load_toolset(
221220
self,
@@ -224,7 +223,7 @@ def load_toolset(
224223
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
225224
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
226225
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
227-
strict: bool = True,
226+
strict: bool = False,
228227
) -> list[ToolboxTool]:
229228
"""
230229
Loads tools from the Toolbox service, optionally filtered by toolset
@@ -239,27 +238,49 @@ def load_toolset(
239238
auth_headers: Deprecated. Use `auth_token_getters` instead.
240239
bound_params: An optional mapping of parameter names to their
241240
bound values.
242-
strict: If True, raises a ValueError if any of the given bound
243-
parameters are missing from the schema or require
244-
authentication. If False, only issues a warning.
241+
strict: If True, raises an error if *any* loaded tool instance fails
242+
to utilize at least one provided parameter or auth token (if any
243+
provided). If False (default), raises an error only if a
244+
user-provided parameter or auth token cannot be applied to *any*
245+
loaded tool across the set.
245246
246247
Returns:
247248
A list of all tools loaded from the Toolbox.
248249
"""
249-
async_tools = self.__run_as_sync(
250-
self.__async_client.aload_toolset(
251-
toolset_name,
252-
auth_token_getters,
253-
auth_tokens,
254-
auth_headers,
255-
bound_params,
256-
strict,
257-
)
250+
if auth_headers:
251+
if auth_token_getters:
252+
warn(
253+
"Both `auth_token_getters` and `auth_headers` are provided. `auth_headers` is deprecated, and `auth_token_getters` will be used.",
254+
DeprecationWarning,
255+
)
256+
else:
257+
warn(
258+
"Argument `auth_headers` is deprecated. Use `auth_token_getters` instead.",
259+
DeprecationWarning,
260+
)
261+
auth_token_getters = auth_headers
262+
263+
if auth_tokens:
264+
if auth_token_getters:
265+
warn(
266+
"Both `auth_token_getters` and `auth_tokens` are provided. `auth_tokens` is deprecated, and `auth_token_getters` will be used.",
267+
DeprecationWarning,
268+
)
269+
else:
270+
warn(
271+
"Argument `auth_tokens` is deprecated. Use `auth_token_getters` instead.",
272+
DeprecationWarning,
273+
)
274+
auth_token_getters = auth_tokens
275+
276+
core_tools = self.__core_sync_client.load_toolset(
277+
name=toolset_name,
278+
auth_token_getters=auth_token_getters,
279+
bound_params=bound_params,
280+
strict=strict
258281
)
259282

260-
if not self.__loop or not self.__thread:
261-
raise ValueError("Background loop or thread cannot be None.")
262-
tools: list[ToolboxTool] = []
263-
for async_tool in async_tools:
264-
tools.append(ToolboxTool(async_tool, self.__loop, self.__thread))
283+
tools = []
284+
for core_tool in core_tools:
285+
tools.append(ToolboxTool(core_tool_instance=core_tool))
265286
return tools

0 commit comments

Comments
 (0)