Custom tools(implemented in "Subclass Basetool" approach) cannot access to state via run_manager #238

Closed
opened 2026-02-20 17:33:25 -05:00 by yindo · 2 comments
Owner

Originally created by @humbroll on GitHub (Sep 19, 2024).

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph/LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangGraph/LangChain rather than my code.
  • I am sure this is better as an issue rather than a GitHub discussion, since this is a LangGraph bug and not a design question.

Example Code

class GooglePlacesTool(BaseTool):
    """Tool that queries the Google places API."""

    name: str = "google_places"
    description: str = (
        "A tool that queries the Google Places API. "
        "Useful for finding places based on a search query. "
        "This tool can help validate addresses or discover locations "
        "from ambiguous text inputs. "
        "Input should be a search query string."
    )
    api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper)  # type: ignore[arg-type]
    args_schema: Type[BaseModel] = GooglePlacesSchema


    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        logger.debug(f"RunManager has state?: {hasattr(run_manager, 'state')}")

        # Run the original tool logic
        result = self.api_wrapper.run(query)

        return result

Error Message and Stack Trace (if applicable)

RunManager has state?: False

Description

How can I access state in a custom tool using the "Subclass Basetool" approach?

System Info

$ pip freeze | grep langchain langchain==0.3.0 langchain-anthropic==0.1.23 langchain-cohere==0.2.4 langchain-community==0.3.0 langchain-core==0.3.0 langchain-experimental==0.0.65 langchain-google-community==2.0.0 langchain-openai==0.2.0 langchain-text-splitters==0.3.0 langchainhub==0.1.21

Originally created by @humbroll on GitHub (Sep 19, 2024). ### Checked other resources - [X] I added a very descriptive title to this issue. - [X] I searched the [LangGraph](https://langchain-ai.github.io/langgraph/)/LangChain documentation with the integrated search. - [X] I used the GitHub search to find a similar question and didn't find it. - [x] I am sure that this is a bug in LangGraph/LangChain rather than my code. - [X] I am sure this is better as an issue [rather than a GitHub discussion](https://github.com/langchain-ai/langgraph/discussions/new/choose), since this is a LangGraph bug and not a design question. ### Example Code ```python class GooglePlacesTool(BaseTool): """Tool that queries the Google places API.""" name: str = "google_places" description: str = ( "A tool that queries the Google Places API. " "Useful for finding places based on a search query. " "This tool can help validate addresses or discover locations " "from ambiguous text inputs. " "Input should be a search query string." ) api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper) # type: ignore[arg-type] args_schema: Type[BaseModel] = GooglePlacesSchema def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None, ) -> str: logger.debug(f"RunManager has state?: {hasattr(run_manager, 'state')}") # Run the original tool logic result = self.api_wrapper.run(query) return result ``` ### Error Message and Stack Trace (if applicable) ```shell RunManager has state?: False ``` ### Description - I'm trying to access states in a custom tool implemented using the "[[Subclass Basetool](https://python.langchain.com/docs/how_to/custom_tools/#subclass-basetool)](https://python.langchain.com/docs/how_to/custom_tools/#subclass-basetool)" approach. - I've confirmed that I can access state with the [["@tool"](https://python.langchain.com/docs/how_to/custom_tools/#tool-decorator)](https://python.langchain.com/docs/how_to/custom_tools/#tool-decorator) decorator method. How can I access state in a custom tool using the "Subclass Basetool" approach? ### System Info `$ pip freeze | grep langchain langchain==0.3.0 langchain-anthropic==0.1.23 langchain-cohere==0.2.4 langchain-community==0.3.0 langchain-core==0.3.0 langchain-experimental==0.0.65 langchain-google-community==2.0.0 langchain-openai==0.2.0 langchain-text-splitters==0.3.0 langchainhub==0.1.21`
yindo closed this issue 2026-02-20 17:33:25 -05:00
Author
Owner

@dikla-avigad commented on GitHub (May 21, 2025):

I had the same issue when trying to access the state from my custom tool, and I was able to resolve it using the following approach - I included the state as part of the tool’s input schema like this:

from typing import Annotated, Callable
from pydantic import BaseModel, Field
from langchain_core.tools import BaseTool
from langgraph.prebuilt import InjectedState
from langchain_core.callbacks import (
    CallbackManagerForToolRun,
    AsyncCallbackManagerForToolRun,
)
import inspect
import logging


class MyAgentState(BaseModel):
    customer: dict

class MyInput(BaseModel):
    query: str = Field(description="A string representing the search query")
    state: Annotated[MyAgentState, InjectedState]

class SearchQueryTool(BaseTool):
    name = "search_query"
    description = "Search for relevant results based on a query"

    def __init__(self, search_client: Callable[[str, str], list[str]]):
        super().__init__()
        self._search_client = search_client
        object.__setattr__(self, "args_schema", MyInput)

    async def _arun(
        self,
        *args: Any,
        run_manager: AsyncCallbackManagerForToolRun | None = None,
        **kwargs: Any
    ) -> Any:
        logger.info(f"[Tool Called] search_query with kwargs: {kwargs}")
        try:
            query = kwargs["query"]
            state: MyAgentState = kwargs["state"]

            # Access injected state
            customer_index = state.customer["index_name"]
            results = await self._search_client(
                index_name=customer_index,
                query=query,
            )
            return results
        except Exception as e:
            logger.exception(f"[Tool Error] search_query")
            raise Exception(f"Tool failed: {e}") from e
@dikla-avigad commented on GitHub (May 21, 2025): I had the same issue when trying to access the state from my custom tool, and I was able to resolve it using the following approach - I included the state as part of the tool’s input schema like this: ```python from typing import Annotated, Callable from pydantic import BaseModel, Field from langchain_core.tools import BaseTool from langgraph.prebuilt import InjectedState from langchain_core.callbacks import ( CallbackManagerForToolRun, AsyncCallbackManagerForToolRun, ) import inspect import logging class MyAgentState(BaseModel): customer: dict class MyInput(BaseModel): query: str = Field(description="A string representing the search query") state: Annotated[MyAgentState, InjectedState] class SearchQueryTool(BaseTool): name = "search_query" description = "Search for relevant results based on a query" def __init__(self, search_client: Callable[[str, str], list[str]]): super().__init__() self._search_client = search_client object.__setattr__(self, "args_schema", MyInput) async def _arun( self, *args: Any, run_manager: AsyncCallbackManagerForToolRun | None = None, **kwargs: Any ) -> Any: logger.info(f"[Tool Called] search_query with kwargs: {kwargs}") try: query = kwargs["query"] state: MyAgentState = kwargs["state"] # Access injected state customer_index = state.customer["index_name"] results = await self._search_client( index_name=customer_index, query=query, ) return results except Exception as e: logger.exception(f"[Tool Error] search_query") raise Exception(f"Tool failed: {e}") from e ```
Author
Owner

@sydney-runkle commented on GitHub (Jun 10, 2025):

Going to close for now given the above workaround, thanks @dikla-avigad!

@sydney-runkle commented on GitHub (Jun 10, 2025): Going to close for now given the above workaround, thanks @dikla-avigad!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#238