Skip to content

feat(toolbox-langchain)!: Base toolbox-langchain over toolbox-core #229

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 53 commits into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
77bfdb2
fix(toolbox-langchain)!: Base toolbox-langchain over toolbox-core
anubhav756 May 8, 2025
53a673c
fix: add toolbox-core as package dependency
anubhav756 May 8, 2025
42f4d35
fix: Base sync client
anubhav756 May 8, 2025
2aeb718
fix: Fix running background asyncio in current loop issue
anubhav756 May 8, 2025
bbc4bba
fix: Base toolbox sync & async tools to toolbox core counterparts
anubhav756 May 8, 2025
56e14cd
fix: Fix getting pydantic model from ToolboxSyncTool
anubhav756 May 8, 2025
44fa98e
fix: Fix issue causing async core tools for creating sync tools
anubhav756 May 8, 2025
f44dc26
fix: Fix reading name from correct param
anubhav756 May 8, 2025
00a3666
fix: Fix issue of unknown parameter due to pydantic initialization
anubhav756 May 8, 2025
24d7a55
fix: Fix nit error + add comment
anubhav756 May 8, 2025
113a312
fix: Fix sync tool name assertion
anubhav756 May 8, 2025
3e09cf2
chore: Temporarily remove unittests
anubhav756 May 8, 2025
c92e5dd
chore: Remove unused strict flag + fix default values + fix docstring
anubhav756 May 8, 2025
d8fd735
fix: Update package to be from git repo
anubhav756 May 9, 2025
595eebe
fix: Fix toolbox-core package local path
anubhav756 May 9, 2025
5f587d4
fix: Fix local package path
anubhav756 May 9, 2025
6f14d52
fix: Update git path
anubhav756 May 9, 2025
9d1ae03
fix: Fix tests
anubhav756 May 9, 2025
dc3a4ff
fix: Fix using correct object for fetching loop
anubhav756 May 9, 2025
c8e6154
fix: Return invoke result
anubhav756 May 9, 2025
b058840
fix: Integration test errors
anubhav756 May 9, 2025
b83b8e3
chore: Delint
anubhav756 May 9, 2025
b771dc4
fix: Fix integration test
anubhav756 May 9, 2025
c2a4e64
fix: Fix integration tests
anubhav756 May 9, 2025
2d917a0
chore: Add unit tests previously deleted
anubhav756 May 9, 2025
395b2a1
chore: Delint
anubhav756 May 9, 2025
6cc15d2
fix: Fix using correct protected member variables
anubhav756 May 9, 2025
1625389
chore: Delint
anubhav756 May 9, 2025
6c224ac
chore: Fix types
anubhav756 May 9, 2025
f8cfe3a
fix: Ensure bg loop/thread not null
anubhav756 May 9, 2025
fb4d742
fix: Check bg loop/thread value
anubhav756 May 9, 2025
36d093b
fix: Revert warnings to prefer auth_tokens over auth_headers
anubhav756 May 9, 2025
248b1db
chore: Update unittests
anubhav756 May 9, 2025
8e2ed29
docs: Improve docstrings
anubhav756 May 10, 2025
3bccd7a
chore: Add TODO note
anubhav756 May 10, 2025
b169c45
chore: Improve TODO note
anubhav756 May 10, 2025
28c62ab
fix: Fix integration test
anubhav756 May 14, 2025
d5c57df
chore: Delint
anubhav756 May 14, 2025
ba29e2d
chore: Rename internal member variable names to be more concise
anubhav756 May 14, 2025
a0f3020
chore: Delint
anubhav756 May 14, 2025
abd6dd8
chore: Add toolbox actual package version in toml and local path in r…
anubhav756 May 15, 2025
f3817b3
fix: Fix editable toolbox-core package path in requirements.txt
anubhav756 May 15, 2025
3562bd7
fix: Fix lowest supported version until released
anubhav756 May 15, 2025
23618c4
fix: Fix issue causing relative path in requirements.txt to cause issues
anubhav756 May 15, 2025
ac535a3
docs: Fix issue README
anubhav756 May 15, 2025
9d3552f
fix: Use correct core client interfaces in langchain client
anubhav756 May 16, 2025
551b113
fix: Use correct core tool interfaces in langchain tool
anubhav756 May 16, 2025
6906393
fix: Use correct interface from core tool
anubhav756 May 16, 2025
f61e81e
fix: Use correct interfaces of toolbox-core
anubhav756 May 16, 2025
9bfb8d1
chore: Update async client unit tests
anubhav756 May 16, 2025
e6cfed2
chore: Fix client unit tests
anubhav756 May 16, 2025
3637bba
chore: Delint
anubhav756 May 16, 2025
9a34f6f
chore: Fix tools unit tests
anubhav756 May 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/toolbox-core/src/toolbox_core/sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def __init__(
async def create_client():
return ToolboxClient(url, client_headers=client_headers)

# Ignoring type since we're already checking the existence of a loop above.
self.__async_client = asyncio.run_coroutine_threadsafe(
create_client(), self.__class__.__loop
).result()
Expand Down
2 changes: 1 addition & 1 deletion packages/toolbox-langchain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ tools = toolbox.load_toolset()

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

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

# OR

Expand Down
3 changes: 2 additions & 1 deletion packages/toolbox-langchain/integration.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
steps:
- id: Install library requirements
name: 'python:${_VERSION}'
dir: 'packages/toolbox-langchain'
args:
- install
- '-r'
- 'packages/toolbox-langchain/requirements.txt'
- 'requirements.txt'
- '--user'
entrypoint: pip
- id: Install test requirements
Expand Down
2 changes: 2 additions & 0 deletions packages/toolbox-langchain/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ authors = [
{name = "Google LLC", email = "googleapis-packages@google.com"}
]
dependencies = [
# TODO: Bump lowest supported version to 0.2.0
"toolbox-core>=0.1.0,<1.0.0",
"langchain-core>=0.2.23,<1.0.0",
"PyYAML>=6.0.1,<7.0.0",
"pydantic>=2.7.0,<3.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/toolbox-langchain/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-e ../toolbox-core
langchain-core==0.3.56
PyYAML==6.0.2
pydantic==2.11.4
Expand Down
66 changes: 25 additions & 41 deletions packages/toolbox-langchain/src/toolbox_langchain/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
from warnings import warn

from aiohttp import ClientSession
from toolbox_core.client import ToolboxClient as ToolboxCoreClient

from .tools import AsyncToolboxTool
from .utils import ManifestSchema, _load_manifest
from .async_tools import AsyncToolboxTool


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

async def aload_tool(
self,
Expand All @@ -48,7 +47,6 @@ async def aload_tool(
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
strict: bool = True,
) -> AsyncToolboxTool:
"""
Loads the tool with the given tool name from the Toolbox service.
Expand All @@ -61,9 +59,6 @@ async def aload_tool(
auth_headers: Deprecated. Use `auth_token_getters` instead.
bound_params: An optional mapping of parameter names to their
bound values.
strict: If True, raises a ValueError if any of the given bound
parameters are missing from the schema or require
authentication. If False, only issues a warning.

Returns:
A tool loaded from the Toolbox.
Expand Down Expand Up @@ -94,18 +89,12 @@ async def aload_tool(
)
auth_token_getters = auth_headers

url = f"{self.__url}/api/tool/{tool_name}"
manifest: ManifestSchema = await _load_manifest(url, self.__session)

return AsyncToolboxTool(
tool_name,
manifest.tools[tool_name],
self.__url,
self.__session,
auth_token_getters,
bound_params,
strict,
core_tool = await self.__core_client.load_tool(
name=tool_name,
auth_token_getters=auth_token_getters,
bound_params=bound_params,
)
return AsyncToolboxTool(core_tool=core_tool)

async def aload_toolset(
self,
Expand All @@ -114,7 +103,7 @@ async def aload_toolset(
auth_tokens: Optional[dict[str, Callable[[], str]]] = None,
auth_headers: Optional[dict[str, Callable[[], str]]] = None,
bound_params: dict[str, Union[Any, Callable[[], Any]]] = {},
strict: bool = True,
strict: bool = False,
) -> list[AsyncToolboxTool]:
"""
Loads tools from the Toolbox service, optionally filtered by toolset
Expand All @@ -129,9 +118,11 @@ async def aload_toolset(
auth_headers: Deprecated. Use `auth_token_getters` instead.
bound_params: An optional mapping of parameter names to their
bound values.
strict: If True, raises a ValueError if any of the given bound
parameters are missing from the schema or require
authentication. If False, only issues a warning.
strict: If True, raises an error if *any* loaded tool instance fails
to utilize at least one provided parameter or auth token (if any
provided). If False (default), raises an error only if a
user-provided parameter or auth token cannot be applied to *any*
loaded tool across the set.

Returns:
A list of all tools loaded from the Toolbox.
Expand Down Expand Up @@ -162,22 +153,16 @@ async def aload_toolset(
)
auth_token_getters = auth_headers

url = f"{self.__url}/api/toolset/{toolset_name or ''}"
manifest: ManifestSchema = await _load_manifest(url, self.__session)
tools: list[AsyncToolboxTool] = []

for tool_name, tool_schema in manifest.tools.items():
tools.append(
AsyncToolboxTool(
tool_name,
tool_schema,
self.__url,
self.__session,
auth_token_getters,
bound_params,
strict,
)
)
core_tools = await self.__core_client.load_toolset(
name=toolset_name,
auth_token_getters=auth_token_getters,
bound_params=bound_params,
strict=strict,
)

tools = []
for core_tool in core_tools:
tools.append(AsyncToolboxTool(core_tool=core_tool))
return tools

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

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