diff --git a/docs/concepts/nodes/agent_node.md b/docs/concepts/nodes/agent_node.md index 0425b459..ce94fccd 100644 --- a/docs/concepts/nodes/agent_node.md +++ b/docs/concepts/nodes/agent_node.md @@ -38,10 +38,33 @@ research_agent: - `tools`: A list of tools that the agent can use. Tools are provided to the agent through the `create_react_agent` function from LangGraph. The following tools are currently supported: - - `tasks.examples.agent_tool_simulation.tools_from_module` All valid tools from a module. - - `tasks.examples.agent_tool_simulation.tools_from_class` All valid tools from a class. + - `tasks.examples.agent_tool_simulation.tools_from_module.tool_method` Single tool method with annotation @tool + - `tasks.examples.agent_tool_simulation.tools_from_module` All valid tools from a module. + - `tasks.examples.agent_tool_simulation.tools_from_module.MyToolClass` All valid tools from a class. Make sure all the necessary tools are decorated with `@tool` from `langchain_core.tools` + If you want to use lang chain tools, make sure to import the necessary libraries, implemented get_tools() by inheriting LangChainToolsWrapper base class. + Below is the PlayWright wrapper class example which can be used in the tools list in agent_node. + ```python + from langchain_community.agent_toolkits import PlayWrightBrowserToolkit + from langchain_community.tools.playwright.utils import ( + create_async_playwright_browser, # A synchronous browser is available, though it isn't compatible with jupyter.\n", }, + ) + + class PlayWrightBrowserTools(LangChainToolsWrapper): + def get_tools(self): + async_browser = create_async_playwright_browser() + toolkit = PlayWrightBrowserToolkit.from_browser(async_browser=async_browser) + pw_tools = toolkit.get_tools() + struct_tools = [] + for t in pw_tools: + try: + struct_tools.append(t.as_tool()) + except Exception as e: + logger.error(f"Failed to get tool: {t}") + continue + return struct_tools + ``` - `inject_system_messages`: Optional dictionary where keys are conversation turn indices and values are additional system messages to inject at those turns. This allows for dynamic guidance of the agent based on conversation length. diff --git a/grasp/utils/tool_utils.py b/grasp/utils/tool_utils.py index fd68e999..ea494d61 100644 --- a/grasp/utils/tool_utils.py +++ b/grasp/utils/tool_utils.py @@ -1,5 +1,5 @@ import importlib -import sys +from abc import ABC, abstractmethod from inspect import isclass, getmembers from typing import List, Callable @@ -9,6 +9,17 @@ from grasp.utils import utils +class LangChainToolsWrapper(ABC): + """ + Inherit this class and implement get_tools() + Which returns tools list to be used directly in the react agent + """ + + @abstractmethod + def get_tools(self) -> list: + pass + + def load_tools(tool_paths: List[str]) -> List[Callable]: """ Load tools from a variety of sources specified in tool_paths. @@ -61,6 +72,10 @@ def load_tools(tool_paths: List[str]) -> List[Callable]: tools.extend(_extract_tools_from_class(obj)) valid = True continue + elif issubclass(tool_func, LangChainToolsWrapper): + tools.extend(tool_func().get_tools()) + valid = True + continue except (ImportError, AttributeError): pass