Skip to content

Commit 03d1b16

Browse files
authored
feat(toolbox-langchain)!: Base toolbox-langchain over toolbox-core (#229)
* fix(toolbox-langchain)!: Base toolbox-langchain over toolbox-core * fix: add toolbox-core as package dependency * fix: Base sync client * fix: Fix running background asyncio in current loop issue * fix: Base toolbox sync & async tools to toolbox core counterparts * fix: Fix getting pydantic model from ToolboxSyncTool * fix: Fix issue causing async core tools for creating sync tools * fix: Fix reading name from correct param * fix: Fix issue of unknown parameter due to pydantic initialization * fix: Fix nit error + add comment * fix: Fix sync tool name assertion * chore: Temporarily remove unittests * chore: Remove unused strict flag + fix default values + fix docstring * fix: Update package to be from git repo * fix: Fix toolbox-core package local path * fix: Fix local package path * fix: Update git path * fix: Fix tests * fix: Fix using correct object for fetching loop * fix: Return invoke result * fix: Integration test errors * chore: Delint * fix: Fix integration test * fix: Fix integration tests * chore: Add unit tests previously deleted * chore: Delint * fix: Fix using correct protected member variables * chore: Delint * chore: Fix types * fix: Ensure bg loop/thread not null * fix: Check bg loop/thread value * fix: Revert warnings to prefer auth_tokens over auth_headers * chore: Update unittests * docs: Improve docstrings * chore: Add TODO note * chore: Improve TODO note * fix: Fix integration test * chore: Delint * chore: Rename internal member variable names to be more concise * chore: Delint * chore: Add toolbox actual package version in toml and local path in requirements.txt * fix: Fix editable toolbox-core package path in requirements.txt * fix: Fix lowest supported version until released * fix: Fix issue causing relative path in requirements.txt to cause issues * docs: Fix issue README * fix: Use correct core client interfaces in langchain client * fix: Use correct core tool interfaces in langchain tool * fix: Use correct interface from core tool * fix: Use correct interfaces of toolbox-core * chore: Update async client unit tests * chore: Fix client unit tests * chore: Delint * chore: Fix tools unit tests
1 parent e9c428b commit 03d1b16

File tree

16 files changed

+1248
-1655
lines changed

16 files changed

+1248
-1655
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def __init__(
5656
async def create_client():
5757
return ToolboxClient(url, client_headers=client_headers)
5858

59-
# Ignoring type since we're already checking the existence of a loop above.
6059
self.__async_client = asyncio.run_coroutine_threadsafe(
6160
create_client(), self.__class__.__loop
6261
).result()

packages/toolbox-langchain/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ tools = toolbox.load_toolset()
227227

228228
auth_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token) # Single token
229229

230-
multi_auth_tool = tools[0].add_auth_token_getters({"my_auth", get_auth_token}) # Multiple tokens
230+
multi_auth_tool = tools[0].add_auth_token_getters({"auth_1": get_auth_1}, {"auth_2": get_auth_2}) # Multiple tokens
231231

232232
# OR
233233

packages/toolbox-langchain/integration.cloudbuild.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
steps:
1616
- id: Install library requirements
1717
name: 'python:${_VERSION}'
18+
dir: 'packages/toolbox-langchain'
1819
args:
1920
- install
2021
- '-r'
21-
- 'packages/toolbox-langchain/requirements.txt'
22+
- 'requirements.txt'
2223
- '--user'
2324
entrypoint: pip
2425
- id: Install test requirements

packages/toolbox-langchain/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ authors = [
99
{name = "Google LLC", email = "[email protected]"}
1010
]
1111
dependencies = [
12+
# TODO: Bump lowest supported version to 0.2.0
13+
"toolbox-core>=0.1.0,<1.0.0",
1214
"langchain-core>=0.2.23,<1.0.0",
1315
"PyYAML>=6.0.1,<7.0.0",
1416
"pydantic>=2.7.0,<3.0.0",

packages/toolbox-langchain/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
-e ../toolbox-core
12
langchain-core==0.3.56
23
PyYAML==6.0.2
34
pydantic==2.11.4

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

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
from warnings import warn
1717

1818
from aiohttp import ClientSession
19+
from toolbox_core.client import ToolboxClient as ToolboxCoreClient
1920

20-
from .tools import AsyncToolboxTool
21-
from .utils import ManifestSchema, _load_manifest
21+
from .async_tools import AsyncToolboxTool
2222

2323

2424
# This class is an internal implementation detail and is not exposed to the
@@ -38,8 +38,7 @@ def __init__(
3838
url: The base URL of the Toolbox service.
3939
session: An HTTP client session.
4040
"""
41-
self.__url = url
42-
self.__session = session
41+
self.__core_client = ToolboxCoreClient(url=url, session=session)
4342

4443
async def aload_tool(
4544
self,
@@ -48,7 +47,6 @@ async def aload_tool(
4847
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
4948
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
5049
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
51-
strict: bool = True,
5250
) -> AsyncToolboxTool:
5351
"""
5452
Loads the tool with the given tool name from the Toolbox service.
@@ -61,9 +59,6 @@ async def aload_tool(
6159
auth_headers: Deprecated. Use `auth_token_getters` instead.
6260
bound_params: An optional mapping of parameter names to their
6361
bound values.
64-
strict: If True, raises a ValueError if any of the given bound
65-
parameters are missing from the schema or require
66-
authentication. If False, only issues a warning.
6762
6863
Returns:
6964
A tool loaded from the Toolbox.
@@ -94,18 +89,12 @@ async def aload_tool(
9489
)
9590
auth_token_getters = auth_headers
9691

97-
url = f"{self.__url}/api/tool/{tool_name}"
98-
manifest: ManifestSchema = await _load_manifest(url, self.__session)
99-
100-
return AsyncToolboxTool(
101-
tool_name,
102-
manifest.tools[tool_name],
103-
self.__url,
104-
self.__session,
105-
auth_token_getters,
106-
bound_params,
107-
strict,
92+
core_tool = await self.__core_client.load_tool(
93+
name=tool_name,
94+
auth_token_getters=auth_token_getters,
95+
bound_params=bound_params,
10896
)
97+
return AsyncToolboxTool(core_tool=core_tool)
10998

11099
async def aload_toolset(
111100
self,
@@ -114,7 +103,7 @@ async def aload_toolset(
114103
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
115104
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
116105
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
117-
strict: bool = True,
106+
strict: bool = False,
118107
) -> list[AsyncToolboxTool]:
119108
"""
120109
Loads tools from the Toolbox service, optionally filtered by toolset
@@ -129,9 +118,11 @@ async def aload_toolset(
129118
auth_headers: Deprecated. Use `auth_token_getters` instead.
130119
bound_params: An optional mapping of parameter names to their
131120
bound values.
132-
strict: If True, raises a ValueError if any of the given bound
133-
parameters are missing from the schema or require
134-
authentication. If False, only issues a warning.
121+
strict: If True, raises an error if *any* loaded tool instance fails
122+
to utilize at least one provided parameter or auth token (if any
123+
provided). If False (default), raises an error only if a
124+
user-provided parameter or auth token cannot be applied to *any*
125+
loaded tool across the set.
135126
136127
Returns:
137128
A list of all tools loaded from the Toolbox.
@@ -162,22 +153,16 @@ async def aload_toolset(
162153
)
163154
auth_token_getters = auth_headers
164155

165-
url = f"{self.__url}/api/toolset/{toolset_name or ''}"
166-
manifest: ManifestSchema = await _load_manifest(url, self.__session)
167-
tools: list[AsyncToolboxTool] = []
168-
169-
for tool_name, tool_schema in manifest.tools.items():
170-
tools.append(
171-
AsyncToolboxTool(
172-
tool_name,
173-
tool_schema,
174-
self.__url,
175-
self.__session,
176-
auth_token_getters,
177-
bound_params,
178-
strict,
179-
)
180-
)
156+
core_tools = await self.__core_client.load_toolset(
157+
name=toolset_name,
158+
auth_token_getters=auth_token_getters,
159+
bound_params=bound_params,
160+
strict=strict,
161+
)
162+
163+
tools = []
164+
for core_tool in core_tools:
165+
tools.append(AsyncToolboxTool(core_tool=core_tool))
181166
return tools
182167

183168
def load_tool(
@@ -187,7 +172,6 @@ def load_tool(
187172
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
188173
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
189174
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
190-
strict: bool = True,
191175
) -> AsyncToolboxTool:
192176
raise NotImplementedError("Synchronous methods not supported by async client.")
193177

@@ -198,6 +182,6 @@ def load_toolset(
198182
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
199183
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
200184
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
201-
strict: bool = True,
185+
strict: bool = False,
202186
) -> list[AsyncToolboxTool]:
203187
raise NotImplementedError("Synchronous methods not supported by async client.")

0 commit comments

Comments
 (0)