libs/core/langchain_core/callbacks/manager.py PYTHON 2,793 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,793.
1"""Run managers."""23from __future__ import annotations45import asyncio6import atexit7import functools8import logging9from abc import ABC, abstractmethod10from collections.abc import Callable, Mapping11from concurrent.futures import ThreadPoolExecutor12from contextlib import asynccontextmanager, contextmanager13from contextvars import copy_context14from typing import TYPE_CHECKING, Any, TypeVar, cast1516from typing_extensions import Self, override1718from langchain_core.callbacks.base import (19    BaseCallbackHandler,20    BaseCallbackManager,21    Callbacks,22    ChainManagerMixin,23    LLMManagerMixin,24    RetrieverManagerMixin,25    RunManagerMixin,26    ToolManagerMixin,27)28from langchain_core.callbacks.stdout import StdOutCallbackHandler29from langchain_core.globals import get_debug30from langchain_core.messages import BaseMessage, get_buffer_string31from langchain_core.utils.env import env_var_is_set32from langchain_core.utils.uuid import uuid73334if TYPE_CHECKING:35    from collections.abc import AsyncGenerator, Coroutine, Generator, Sequence36    from uuid import UUID3738    from langchain_protocol.protocol import MessagesData39    from tenacity import RetryCallState4041    from langchain_core.agents import AgentAction, AgentFinish42    from langchain_core.documents import Document43    from langchain_core.outputs import ChatGenerationChunk, GenerationChunk, LLMResult44    from langchain_core.runnables.config import RunnableConfig45    from langchain_core.tracers.schemas import Run4647logger = logging.getLogger(__name__)484950def _get_debug() -> bool:51    return get_debug()525354@contextmanager55def trace_as_chain_group(56    group_name: str,57    callback_manager: CallbackManager | None = None,58    *,59    inputs: dict[str, Any] | None = None,60    project_name: str | None = None,61    example_id: str | UUID | None = None,62    run_id: UUID | None = None,63    tags: list[str] | None = None,64    metadata: dict[str, Any] | None = None,65) -> Generator[CallbackManagerForChainGroup, None, None]:66    """Get a callback manager for a chain group in a context manager.6768    Useful for grouping different calls together as a single run even if they aren't69    composed in a single chain.7071    Args:72        group_name: The name of the chain group.73        callback_manager: The callback manager to use.74        inputs: The inputs to the chain group.75        project_name: The name of the project.76        example_id: The ID of the example.77        run_id: The ID of the run.78        tags: The inheritable tags to apply to all runs.79        metadata: The metadata to apply to all runs.8081    !!! note8283        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in84        LangSmith.8586    Yields:87        The callback manager for the chain group.8889    Example:90        ```python91        llm_input = "Foo"92        with trace_as_chain_group("group_name", inputs={"input": llm_input}) as manager:93            # Use the callback manager for the chain group94            res = llm.invoke(llm_input, {"callbacks": manager})95            manager.on_chain_end({"output": res})96        ```97    """98    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level99        _get_trace_callbacks,100    )101102    cb = _get_trace_callbacks(103        project_name, example_id, callback_manager=callback_manager104    )105    cm = CallbackManager.configure(106        inheritable_callbacks=cb,107        inheritable_tags=tags,108        inheritable_metadata=metadata,109    )110111    run_manager = cm.on_chain_start({"name": group_name}, inputs or {}, run_id=run_id)112    child_cm = run_manager.get_child()113    group_cm = CallbackManagerForChainGroup(114        child_cm.handlers,115        child_cm.inheritable_handlers,116        child_cm.parent_run_id,117        parent_run_manager=run_manager,118        tags=child_cm.tags,119        inheritable_tags=child_cm.inheritable_tags,120        metadata=child_cm.metadata,121        inheritable_metadata=child_cm.inheritable_metadata,122    )123    try:124        yield group_cm125    except Exception as e:126        if not group_cm.ended:127            run_manager.on_chain_error(e)128        raise129    else:130        if not group_cm.ended:131            run_manager.on_chain_end({})132133134@asynccontextmanager135async def atrace_as_chain_group(136    group_name: str,137    callback_manager: AsyncCallbackManager | None = None,138    *,139    inputs: dict[str, Any] | None = None,140    project_name: str | None = None,141    example_id: str | UUID | None = None,142    run_id: UUID | None = None,143    tags: list[str] | None = None,144    metadata: dict[str, Any] | None = None,145) -> AsyncGenerator[AsyncCallbackManagerForChainGroup, None]:146    """Get an async callback manager for a chain group in a context manager.147148    Useful for grouping different async calls together as a single run even if they149    aren't composed in a single chain.150151    Args:152        group_name: The name of the chain group.153        callback_manager: The async callback manager to use, which manages tracing and154            other callback behavior.155        inputs: The inputs to the chain group.156        project_name: The name of the project.157        example_id: The ID of the example.158        run_id: The ID of the run.159        tags: The inheritable tags to apply to all runs.160        metadata: The metadata to apply to all runs.161162    Yields:163        The async callback manager for the chain group.164165    !!! note166167        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in168        LangSmith.169170    Example:171        ```python172        llm_input = "Foo"173        async with atrace_as_chain_group(174            "group_name", inputs={"input": llm_input}175        ) as manager:176            # Use the async callback manager for the chain group177            res = await llm.ainvoke(llm_input, {"callbacks": manager})178            await manager.on_chain_end({"output": res})179        ```180    """181    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level182        _get_trace_callbacks,183    )184185    cb = _get_trace_callbacks(186        project_name, example_id, callback_manager=callback_manager187    )188    cm = AsyncCallbackManager.configure(189        inheritable_callbacks=cb, inheritable_tags=tags, inheritable_metadata=metadata190    )191192    run_manager = await cm.on_chain_start(193        {"name": group_name}, inputs or {}, run_id=run_id194    )195    child_cm = run_manager.get_child()196    group_cm = AsyncCallbackManagerForChainGroup(197        child_cm.handlers,198        child_cm.inheritable_handlers,199        child_cm.parent_run_id,200        parent_run_manager=run_manager,201        tags=child_cm.tags,202        inheritable_tags=child_cm.inheritable_tags,203        metadata=child_cm.metadata,204        inheritable_metadata=child_cm.inheritable_metadata,205    )206    try:207        yield group_cm208    except Exception as e:209        if not group_cm.ended:210            await run_manager.on_chain_error(e)211        raise212    else:213        if not group_cm.ended:214            await run_manager.on_chain_end({})215216217Func = TypeVar("Func", bound=Callable)218219220def shielded(func: Func) -> Func:221    """Makes so an awaitable method is always shielded from cancellation.222223    Args:224        func: The function to shield.225226    Returns:227        The shielded function228229    """230231    @functools.wraps(func)232    async def wrapped(*args: Any, **kwargs: Any) -> Any:233        # Capture the current context to preserve context variables234        ctx = copy_context()235236        # Create the coroutine237        coro = func(*args, **kwargs)238239        # For Python 3.11+, create task with explicit context240        # For older versions, fallback to original behavior241        try:242            # Create a task with the captured context to preserve context variables243            task = asyncio.create_task(coro, context=ctx)  # type: ignore[call-arg, unused-ignore]244            # `call-arg` used to not fail 3.9 or 3.10 tests245            return await asyncio.shield(task)246        except TypeError:247            # Python < 3.11 fallback - create task normally then shield248            # This won't preserve context perfectly but is better than nothing249            task = asyncio.create_task(coro)250            return await asyncio.shield(task)251252    return cast("Func", wrapped)253254255def handle_event(256    handlers: list[BaseCallbackHandler],257    event_name: str,258    ignore_condition_name: str | None,259    *args: Any,260    **kwargs: Any,261) -> None:262    """Generic event handler for `CallbackManager`.263264    Args:265        handlers: The list of handlers that will handle the event.266        event_name: The name of the event (e.g., `'on_llm_start'`).267        ignore_condition_name: Name of the attribute defined on handler that if `True`268            will cause the handler to be skipped for the given event.269        *args: The arguments to pass to the event handler.270        **kwargs: The keyword arguments to pass to the event handler271272    """273    coros: list[Coroutine[Any, Any, Any]] = []274275    try:276        message_strings: list[str] | None = None277        for handler in handlers:278            try:279                if ignore_condition_name is None or not getattr(280                    handler, ignore_condition_name281                ):282                    event = getattr(handler, event_name)(*args, **kwargs)283                    if asyncio.iscoroutine(event):284                        coros.append(event)285            except NotImplementedError as e:286                if event_name == "on_chat_model_start":287                    if message_strings is None:288                        message_strings = [get_buffer_string(m) for m in args[1]]289                    handle_event(290                        [handler],291                        "on_llm_start",292                        "ignore_llm",293                        args[0],294                        message_strings,295                        *args[2:],296                        **kwargs,297                    )298                else:299                    handler_name = handler.__class__.__name__300                    logger.warning(301                        "NotImplementedError in %s.%s callback: %s",302                        handler_name,303                        event_name,304                        repr(e),305                    )306            except Exception as e:307                logger.warning(308                    "Error in %s.%s callback: %s",309                    handler.__class__.__name__,310                    event_name,311                    repr(e),312                )313                if handler.raise_error:314                    raise315    finally:316        if coros:317            try:318                # Raises RuntimeError if there is no current event loop.319                asyncio.get_running_loop()320                loop_running = True321            except RuntimeError:322                loop_running = False323324            if loop_running:325                # If we try to submit this coroutine to the running loop326                # we end up in a deadlock, as we'd have gotten here from a327                # running coroutine, which we cannot interrupt to run this one.328                # The solution is to run the synchronous function on the globally shared329                # thread pool executor to avoid blocking the main event loop.330                _executor().submit(331                    cast("Callable", copy_context().run), _run_coros, coros332                ).result()333            else:334                # If there's no running loop, we can run the coroutines directly.335                _run_coros(coros)336337338def _run_coros(coros: list[Coroutine[Any, Any, Any]]) -> None:339    if hasattr(asyncio, "Runner"):340        # Python 3.11+341        # Run the coroutines in a new event loop, taking care to342        # - install signal handlers343        # - run pending tasks scheduled by `coros`344        # - close asyncgens and executors345        # - close the loop346        with asyncio.Runner() as runner:347            # Run the coroutine, get the result348            for coro in coros:349                try:350                    runner.run(coro)351                except Exception as e:352                    logger.warning("Error in callback coroutine: %s", repr(e))353354            # Run pending tasks scheduled by coros until they are all done355            while pending := asyncio.all_tasks(runner.get_loop()):356                runner.run(asyncio.wait(pending))357    else:358        # Before Python 3.11 we need to run each coroutine in a new event loop359        # as the Runner api is not available.360        for coro in coros:361            try:362                asyncio.run(coro)363            except Exception as e:364                logger.warning("Error in callback coroutine: %s", repr(e))365366367async def _ahandle_event_for_handler(368    handler: BaseCallbackHandler,369    event_name: str,370    ignore_condition_name: str | None,371    *args: Any,372    **kwargs: Any,373) -> None:374    try:375        if ignore_condition_name is None or not getattr(handler, ignore_condition_name):376            event = getattr(handler, event_name)377            if asyncio.iscoroutinefunction(event):378                await event(*args, **kwargs)379            elif handler.run_inline:380                event(*args, **kwargs)381            else:382                await asyncio.get_event_loop().run_in_executor(383                    None,384                    cast(385                        "Callable",386                        functools.partial(copy_context().run, event, *args, **kwargs),387                    ),388                )389    except NotImplementedError as e:390        if event_name == "on_chat_model_start":391            message_strings = [get_buffer_string(m) for m in args[1]]392            await _ahandle_event_for_handler(393                handler,394                "on_llm_start",395                "ignore_llm",396                args[0],397                message_strings,398                *args[2:],399                **kwargs,400            )401        else:402            logger.warning(403                "NotImplementedError in %s.%s callback: %s",404                handler.__class__.__name__,405                event_name,406                repr(e),407            )408    except Exception as e:409        logger.warning(410            "Error in %s.%s callback: %s",411            handler.__class__.__name__,412            event_name,413            repr(e),414        )415        if handler.raise_error:416            raise417418419async def ahandle_event(420    handlers: list[BaseCallbackHandler],421    event_name: str,422    ignore_condition_name: str | None,423    *args: Any,424    **kwargs: Any,425) -> None:426    """Async generic event handler for `AsyncCallbackManager`.427428    Args:429        handlers: The list of handlers that will handle the event.430        event_name: The name of the event (e.g., `'on_llm_start'`).431        ignore_condition_name: Name of the attribute defined on handler that if `True`432            will cause the handler to be skipped for the given event.433        *args: The arguments to pass to the event handler.434        **kwargs: The keyword arguments to pass to the event handler.435436    """437    for handler in [h for h in handlers if h.run_inline]:438        await _ahandle_event_for_handler(439            handler, event_name, ignore_condition_name, *args, **kwargs440        )441    await asyncio.gather(442        *(443            _ahandle_event_for_handler(444                handler,445                event_name,446                ignore_condition_name,447                *args,448                **kwargs,449            )450            for handler in handlers451            if not handler.run_inline452        )453    )454455456class BaseRunManager(RunManagerMixin):457    """Base class for run manager (a bound callback manager)."""458459    def __init__(460        self,461        *,462        run_id: UUID,463        handlers: list[BaseCallbackHandler],464        inheritable_handlers: list[BaseCallbackHandler],465        parent_run_id: UUID | None = None,466        tags: list[str] | None = None,467        inheritable_tags: list[str] | None = None,468        metadata: dict[str, Any] | None = None,469        inheritable_metadata: dict[str, Any] | None = None,470    ) -> None:471        """Initialize the run manager.472473        Args:474            run_id: The ID of the run.475            handlers: The list of handlers.476            inheritable_handlers: The list of inheritable handlers.477            parent_run_id: The ID of the parent run.478            tags: The list of tags.479            inheritable_tags: The list of inheritable tags.480            metadata: The metadata.481            inheritable_metadata: The inheritable metadata.482483        """484        self.run_id = run_id485        self.handlers = handlers486        self.inheritable_handlers = inheritable_handlers487        self.parent_run_id = parent_run_id488        self.tags = tags or []489        self.inheritable_tags = inheritable_tags or []490        self.metadata = metadata or {}491        self.inheritable_metadata = inheritable_metadata or {}492493    @classmethod494    def get_noop_manager(cls) -> Self:495        """Return a manager that doesn't perform any operations.496497        Returns:498            The noop manager.499500        """501        return cls(502            run_id=uuid7(),503            handlers=[],504            inheritable_handlers=[],505            tags=[],506            inheritable_tags=[],507            metadata={},508            inheritable_metadata={},509        )510511512class RunManager(BaseRunManager):513    """Synchronous run manager."""514515    def on_text(516        self,517        text: str,518        **kwargs: Any,519    ) -> None:520        """Run when a text is received.521522        Args:523            text: The received text.524            **kwargs: Additional keyword arguments.525        """526        if not self.handlers:527            return528        handle_event(529            self.handlers,530            "on_text",531            None,532            text,533            run_id=self.run_id,534            parent_run_id=self.parent_run_id,535            tags=self.tags,536            **kwargs,537        )538539    def on_retry(540        self,541        retry_state: RetryCallState,542        **kwargs: Any,543    ) -> None:544        """Run when a retry is received.545546        Args:547            retry_state: The retry state.548            **kwargs: Additional keyword arguments.549550        """551        if not self.handlers:552            return553        handle_event(554            self.handlers,555            "on_retry",556            "ignore_retry",557            retry_state,558            run_id=self.run_id,559            parent_run_id=self.parent_run_id,560            tags=self.tags,561            **kwargs,562        )563564565class ParentRunManager(RunManager):566    """Synchronous parent run manager."""567568    def get_child(self, tag: str | None = None) -> CallbackManager:569        """Get a child callback manager.570571        Args:572            tag: The tag for the child callback manager.573574        Returns:575            The child callback manager.576577        """578        manager = CallbackManager(handlers=[], parent_run_id=self.run_id)579        manager.set_handlers(self.inheritable_handlers)580        manager.add_tags(self.inheritable_tags)581        manager.add_metadata(self.inheritable_metadata)582        if tag is not None:583            manager.add_tags([tag], inherit=False)584        return manager585586587class AsyncRunManager(BaseRunManager, ABC):588    """Async run manager."""589590    @abstractmethod591    def get_sync(self) -> RunManager:592        """Get the equivalent sync `RunManager`.593594        Returns:595            The sync `RunManager`.596597        """598599    async def on_text(600        self,601        text: str,602        **kwargs: Any,603    ) -> None:604        """Run when a text is received.605606        Args:607            text: The received text.608            **kwargs: Additional keyword arguments.609        """610        if not self.handlers:611            return612        await ahandle_event(613            self.handlers,614            "on_text",615            None,616            text,617            run_id=self.run_id,618            parent_run_id=self.parent_run_id,619            tags=self.tags,620            **kwargs,621        )622623    async def on_retry(624        self,625        retry_state: RetryCallState,626        **kwargs: Any,627    ) -> None:628        """Async run when a retry is received.629630        Args:631            retry_state: The retry state.632            **kwargs: Additional keyword arguments.633634        """635        if not self.handlers:636            return637        await ahandle_event(638            self.handlers,639            "on_retry",640            "ignore_retry",641            retry_state,642            run_id=self.run_id,643            parent_run_id=self.parent_run_id,644            tags=self.tags,645            **kwargs,646        )647648649class AsyncParentRunManager(AsyncRunManager):650    """Async parent run manager."""651652    def get_child(self, tag: str | None = None) -> AsyncCallbackManager:653        """Get a child callback manager.654655        Args:656            tag: The tag for the child callback manager.657658        Returns:659            The child callback manager.660661        """662        manager = AsyncCallbackManager(handlers=[], parent_run_id=self.run_id)663        manager.set_handlers(self.inheritable_handlers)664        manager.add_tags(self.inheritable_tags)665        manager.add_metadata(self.inheritable_metadata)666        if tag is not None:667            manager.add_tags([tag], inherit=False)668        return manager669670671class CallbackManagerForLLMRun(RunManager, LLMManagerMixin):672    """Callback manager for LLM run."""673674    def on_llm_new_token(675        self,676        token: str,677        *,678        chunk: GenerationChunk | ChatGenerationChunk | None = None,679        **kwargs: Any,680    ) -> None:681        """Run when LLM generates a new token.682683        Args:684            token: The new token.685            chunk: The chunk.686            **kwargs: Additional keyword arguments.687688        """689        if not self.handlers:690            return691        handle_event(692            self.handlers,693            "on_llm_new_token",694            "ignore_llm",695            token=token,696            run_id=self.run_id,697            parent_run_id=self.parent_run_id,698            tags=self.tags,699            chunk=chunk,700            **kwargs,701        )702703    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:704        """Run when LLM ends running.705706        Args:707            response: The LLM result.708            **kwargs: Additional keyword arguments.709710        """711        if not self.handlers:712            return713        handle_event(714            self.handlers,715            "on_llm_end",716            "ignore_llm",717            response,718            run_id=self.run_id,719            parent_run_id=self.parent_run_id,720            tags=self.tags,721            **kwargs,722        )723724    def on_llm_error(725        self,726        error: BaseException,727        **kwargs: Any,728    ) -> None:729        """Run when LLM errors.730731        Args:732            error: The error.733            **kwargs: Additional keyword arguments.734735                - response (LLMResult): The response which was generated before736                    the error occurred.737        """738        if not self.handlers:739            return740        handle_event(741            self.handlers,742            "on_llm_error",743            "ignore_llm",744            error,745            run_id=self.run_id,746            parent_run_id=self.parent_run_id,747            tags=self.tags,748            **kwargs,749        )750751    def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:752        """Run on each protocol event from `stream_events(version="v3")`.753754        Args:755            event: The protocol event.756            **kwargs: Additional keyword arguments.757        """758        if not self.handlers:759            return760        handle_event(761            self.handlers,762            "on_stream_event",763            "ignore_llm",764            event,765            run_id=self.run_id,766            parent_run_id=self.parent_run_id,767            tags=self.tags,768            **kwargs,769        )770771772class AsyncCallbackManagerForLLMRun(AsyncRunManager, LLMManagerMixin):773    """Async callback manager for LLM run."""774775    def get_sync(self) -> CallbackManagerForLLMRun:776        """Get the equivalent sync `RunManager`.777778        Returns:779            The sync `RunManager`.780781        """782        return CallbackManagerForLLMRun(783            run_id=self.run_id,784            handlers=self.handlers,785            inheritable_handlers=self.inheritable_handlers,786            parent_run_id=self.parent_run_id,787            tags=self.tags,788            inheritable_tags=self.inheritable_tags,789            metadata=self.metadata,790            inheritable_metadata=self.inheritable_metadata,791        )792793    async def on_llm_new_token(794        self,795        token: str,796        *,797        chunk: GenerationChunk | ChatGenerationChunk | None = None,798        **kwargs: Any,799    ) -> None:800        """Run when LLM generates a new token.801802        Args:803            token: The new token.804            chunk: The chunk.805            **kwargs: Additional keyword arguments.806807        """808        if not self.handlers:809            return810        await ahandle_event(811            self.handlers,812            "on_llm_new_token",813            "ignore_llm",814            token,815            chunk=chunk,816            run_id=self.run_id,817            parent_run_id=self.parent_run_id,818            tags=self.tags,819            **kwargs,820        )821822    @shielded823    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:824        """Run when LLM ends running.825826        Args:827            response: The LLM result.828            **kwargs: Additional keyword arguments.829830        """831        if not self.handlers:832            return833        await ahandle_event(834            self.handlers,835            "on_llm_end",836            "ignore_llm",837            response,838            run_id=self.run_id,839            parent_run_id=self.parent_run_id,840            tags=self.tags,841            **kwargs,842        )843844    @shielded845    async def on_llm_error(846        self,847        error: BaseException,848        **kwargs: Any,849    ) -> None:850        """Run when LLM errors.851852        Args:853            error: The error.854            **kwargs: Additional keyword arguments.855856                - response (LLMResult): The response which was generated before857                    the error occurred.858859        """860        if not self.handlers:861            return862        await ahandle_event(863            self.handlers,864            "on_llm_error",865            "ignore_llm",866            error,867            run_id=self.run_id,868            parent_run_id=self.parent_run_id,869            tags=self.tags,870            **kwargs,871        )872873    async def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:874        """Run on each protocol event from `astream_events(version="v3")`.875876        Args:877            event: The protocol event.878            **kwargs: Additional keyword arguments.879        """880        if not self.handlers:881            return882        await ahandle_event(883            self.handlers,884            "on_stream_event",885            "ignore_llm",886            event,887            run_id=self.run_id,888            parent_run_id=self.parent_run_id,889            tags=self.tags,890            **kwargs,891        )892893894class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):895    """Callback manager for chain run."""896897    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:898        """Run when chain ends running.899900        Args:901            outputs: The outputs of the chain.902            **kwargs: Additional keyword arguments.903904        """905        if not self.handlers:906            return907        handle_event(908            self.handlers,909            "on_chain_end",910            "ignore_chain",911            outputs,912            run_id=self.run_id,913            parent_run_id=self.parent_run_id,914            tags=self.tags,915            **kwargs,916        )917918    def on_chain_error(919        self,920        error: BaseException,921        **kwargs: Any,922    ) -> None:923        """Run when chain errors.924925        Args:926            error: The error.927            **kwargs: Additional keyword arguments.928929        """930        if not self.handlers:931            return932        handle_event(933            self.handlers,934            "on_chain_error",935            "ignore_chain",936            error,937            run_id=self.run_id,938            parent_run_id=self.parent_run_id,939            tags=self.tags,940            **kwargs,941        )942943    def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:944        """Run when agent action is received.945946        Args:947            action: The agent action.948            **kwargs: Additional keyword arguments.949        """950        if not self.handlers:951            return952        handle_event(953            self.handlers,954            "on_agent_action",955            "ignore_agent",956            action,957            run_id=self.run_id,958            parent_run_id=self.parent_run_id,959            tags=self.tags,960            **kwargs,961        )962963    def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:964        """Run when agent finish is received.965966        Args:967            finish: The agent finish.968            **kwargs: Additional keyword arguments.969        """970        if not self.handlers:971            return972        handle_event(973            self.handlers,974            "on_agent_finish",975            "ignore_agent",976            finish,977            run_id=self.run_id,978            parent_run_id=self.parent_run_id,979            tags=self.tags,980            **kwargs,981        )982983984class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):985    """Async callback manager for chain run."""986987    def get_sync(self) -> CallbackManagerForChainRun:988        """Get the equivalent sync `RunManager`.989990        Returns:991            The sync `RunManager`.992        """993        return CallbackManagerForChainRun(994            run_id=self.run_id,995            handlers=self.handlers,996            inheritable_handlers=self.inheritable_handlers,997            parent_run_id=self.parent_run_id,998            tags=self.tags,999            inheritable_tags=self.inheritable_tags,1000            metadata=self.metadata,1001            inheritable_metadata=self.inheritable_metadata,1002        )10031004    @shielded1005    async def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1006        """Run when a chain ends running.10071008        Args:1009            outputs: The outputs of the chain.1010            **kwargs: Additional keyword arguments.10111012        """1013        if not self.handlers:1014            return1015        await ahandle_event(1016            self.handlers,1017            "on_chain_end",1018            "ignore_chain",1019            outputs,1020            run_id=self.run_id,1021            parent_run_id=self.parent_run_id,1022            tags=self.tags,1023            **kwargs,1024        )10251026    @shielded1027    async def on_chain_error(1028        self,1029        error: BaseException,1030        **kwargs: Any,1031    ) -> None:1032        """Run when chain errors.10331034        Args:1035            error: The error.1036            **kwargs: Additional keyword arguments.10371038        """1039        if not self.handlers:1040            return1041        await ahandle_event(1042            self.handlers,1043            "on_chain_error",1044            "ignore_chain",1045            error,1046            run_id=self.run_id,1047            parent_run_id=self.parent_run_id,1048            tags=self.tags,1049            **kwargs,1050        )10511052    async def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:1053        """Run when agent action is received.10541055        Args:1056            action: The agent action.1057            **kwargs: Additional keyword arguments.1058        """1059        if not self.handlers:1060            return1061        await ahandle_event(1062            self.handlers,1063            "on_agent_action",1064            "ignore_agent",1065            action,1066            run_id=self.run_id,1067            parent_run_id=self.parent_run_id,1068            tags=self.tags,1069            **kwargs,1070        )10711072    async def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:1073        """Run when agent finish is received.10741075        Args:1076            finish: The agent finish.1077            **kwargs: Additional keyword arguments.1078        """1079        if not self.handlers:1080            return1081        await ahandle_event(1082            self.handlers,1083            "on_agent_finish",1084            "ignore_agent",1085            finish,1086            run_id=self.run_id,1087            parent_run_id=self.parent_run_id,1088            tags=self.tags,1089            **kwargs,1090        )109110921093class CallbackManagerForToolRun(ParentRunManager, ToolManagerMixin):1094    """Callback manager for tool run."""10951096    def on_tool_end(1097        self,1098        output: Any,1099        **kwargs: Any,1100    ) -> None:1101        """Run when the tool ends running.11021103        Args:1104            output: The output of the tool.1105            **kwargs: The keyword arguments to pass to the event handler11061107        """1108        if not self.handlers:1109            return1110        handle_event(1111            self.handlers,1112            "on_tool_end",1113            "ignore_agent",1114            output,1115            run_id=self.run_id,1116            parent_run_id=self.parent_run_id,1117            tags=self.tags,1118            **kwargs,1119        )11201121    def on_tool_error(1122        self,1123        error: BaseException,1124        **kwargs: Any,1125    ) -> None:1126        """Run when tool errors.11271128        Args:1129            error: The error.1130            **kwargs: Additional keyword arguments.11311132        """1133        if not self.handlers:1134            return1135        handle_event(1136            self.handlers,1137            "on_tool_error",1138            "ignore_agent",1139            error,1140            run_id=self.run_id,1141            parent_run_id=self.parent_run_id,1142            tags=self.tags,1143            **kwargs,1144        )114511461147class AsyncCallbackManagerForToolRun(AsyncParentRunManager, ToolManagerMixin):1148    """Async callback manager for tool run."""11491150    def get_sync(self) -> CallbackManagerForToolRun:1151        """Get the equivalent sync `RunManager`.11521153        Returns:1154            The sync `RunManager`.1155        """1156        return CallbackManagerForToolRun(1157            run_id=self.run_id,1158            handlers=self.handlers,1159            inheritable_handlers=self.inheritable_handlers,1160            parent_run_id=self.parent_run_id,1161            tags=self.tags,1162            inheritable_tags=self.inheritable_tags,1163            metadata=self.metadata,1164            inheritable_metadata=self.inheritable_metadata,1165        )11661167    async def on_tool_end(self, output: Any, **kwargs: Any) -> None:1168        """Async run when the tool ends running.11691170        Args:1171            output: The output of the tool.1172            **kwargs: Additional keyword arguments.11731174        """1175        if not self.handlers:1176            return1177        await ahandle_event(1178            self.handlers,1179            "on_tool_end",1180            "ignore_agent",1181            output,1182            run_id=self.run_id,1183            parent_run_id=self.parent_run_id,1184            tags=self.tags,1185            **kwargs,1186        )11871188    async def on_tool_error(1189        self,1190        error: BaseException,1191        **kwargs: Any,1192    ) -> None:1193        """Run when tool errors.11941195        Args:1196            error: The error.1197            **kwargs: Additional keyword arguments.11981199        """1200        if not self.handlers:1201            return1202        await ahandle_event(1203            self.handlers,1204            "on_tool_error",1205            "ignore_agent",1206            error,1207            run_id=self.run_id,1208            parent_run_id=self.parent_run_id,1209            tags=self.tags,1210            **kwargs,1211        )121212131214class CallbackManagerForRetrieverRun(ParentRunManager, RetrieverManagerMixin):1215    """Callback manager for retriever run."""12161217    def on_retriever_end(1218        self,1219        documents: Sequence[Document],1220        **kwargs: Any,1221    ) -> None:1222        """Run when retriever ends running.12231224        Args:1225            documents: The retrieved documents.1226            **kwargs: Additional keyword arguments.12271228        """1229        if not self.handlers:1230            return1231        handle_event(1232            self.handlers,1233            "on_retriever_end",1234            "ignore_retriever",1235            documents,1236            run_id=self.run_id,1237            parent_run_id=self.parent_run_id,1238            tags=self.tags,1239            **kwargs,1240        )12411242    def on_retriever_error(1243        self,1244        error: BaseException,1245        **kwargs: Any,1246    ) -> None:1247        """Run when retriever errors.12481249        Args:1250            error: The error.1251            **kwargs: Additional keyword arguments.12521253        """1254        if not self.handlers:1255            return1256        handle_event(1257            self.handlers,1258            "on_retriever_error",1259            "ignore_retriever",1260            error,1261            run_id=self.run_id,1262            parent_run_id=self.parent_run_id,1263            tags=self.tags,1264            **kwargs,1265        )126612671268class AsyncCallbackManagerForRetrieverRun(1269    AsyncParentRunManager,1270    RetrieverManagerMixin,1271):1272    """Async callback manager for retriever run."""12731274    def get_sync(self) -> CallbackManagerForRetrieverRun:1275        """Get the equivalent sync `RunManager`.12761277        Returns:1278            The sync `RunManager`.12791280        """1281        return CallbackManagerForRetrieverRun(1282            run_id=self.run_id,1283            handlers=self.handlers,1284            inheritable_handlers=self.inheritable_handlers,1285            parent_run_id=self.parent_run_id,1286            tags=self.tags,1287            inheritable_tags=self.inheritable_tags,1288            metadata=self.metadata,1289            inheritable_metadata=self.inheritable_metadata,1290        )12911292    @shielded1293    async def on_retriever_end(1294        self, documents: Sequence[Document], **kwargs: Any1295    ) -> None:1296        """Run when the retriever ends running.12971298        Args:1299            documents: The retrieved documents.1300            **kwargs: Additional keyword arguments.13011302        """1303        if not self.handlers:1304            return1305        await ahandle_event(1306            self.handlers,1307            "on_retriever_end",1308            "ignore_retriever",1309            documents,1310            run_id=self.run_id,1311            parent_run_id=self.parent_run_id,1312            tags=self.tags,1313            **kwargs,1314        )13151316    @shielded1317    async def on_retriever_error(1318        self,1319        error: BaseException,1320        **kwargs: Any,1321    ) -> None:1322        """Run when retriever errors.13231324        Args:1325            error: The error.1326            **kwargs: Additional keyword arguments.13271328        """1329        if not self.handlers:1330            return1331        await ahandle_event(1332            self.handlers,1333            "on_retriever_error",1334            "ignore_retriever",1335            error,1336            run_id=self.run_id,1337            parent_run_id=self.parent_run_id,1338            tags=self.tags,1339            **kwargs,1340        )134113421343class CallbackManager(BaseCallbackManager):1344    """Callback manager for LangChain."""13451346    def on_llm_start(1347        self,1348        serialized: dict[str, Any],1349        prompts: list[str],1350        run_id: UUID | None = None,1351        **kwargs: Any,1352    ) -> list[CallbackManagerForLLMRun]:1353        """Run when LLM starts running.13541355        Args:1356            serialized: The serialized LLM.1357            prompts: The list of prompts.1358            run_id: The ID of the run.1359            **kwargs: Additional keyword arguments.13601361        Returns:1362            A callback manager for each prompt as an LLM run.13631364        """1365        managers = []1366        for i, prompt in enumerate(prompts):1367            # Can't have duplicate runs with the same run ID (if provided)1368            run_id_ = run_id if i == 0 and run_id is not None else uuid7()1369            handle_event(1370                self.handlers,1371                "on_llm_start",1372                "ignore_llm",1373                serialized,1374                [prompt],1375                run_id=run_id_,1376                parent_run_id=self.parent_run_id,1377                tags=self.tags,1378                metadata=self.metadata,1379                **kwargs,1380            )13811382            managers.append(1383                CallbackManagerForLLMRun(1384                    run_id=run_id_,1385                    handlers=self.handlers,1386                    inheritable_handlers=self.inheritable_handlers,1387                    parent_run_id=self.parent_run_id,1388                    tags=self.tags,1389                    inheritable_tags=self.inheritable_tags,1390                    metadata=self.metadata,1391                    inheritable_metadata=self.inheritable_metadata,1392                )1393            )13941395        return managers13961397    def on_chat_model_start(1398        self,1399        serialized: dict[str, Any],1400        messages: list[list[BaseMessage]],1401        run_id: UUID | None = None,1402        **kwargs: Any,1403    ) -> list[CallbackManagerForLLMRun]:1404        """Run when chat model starts running.14051406        Args:1407            serialized: The serialized LLM.1408            messages: The list of messages.1409            run_id: The ID of the run.1410            **kwargs: Additional keyword arguments.14111412        Returns:1413            A callback manager for each list of messages as an LLM run.14141415        """1416        managers = []1417        for message_list in messages:1418            if run_id is not None:1419                run_id_ = run_id1420                run_id = None1421            else:1422                run_id_ = uuid7()1423            handle_event(1424                self.handlers,1425                "on_chat_model_start",1426                "ignore_chat_model",1427                serialized,1428                [message_list],1429                run_id=run_id_,1430                parent_run_id=self.parent_run_id,1431                tags=self.tags,1432                metadata=self.metadata,1433                **kwargs,1434            )14351436            managers.append(1437                CallbackManagerForLLMRun(1438                    run_id=run_id_,1439                    handlers=self.handlers,1440                    inheritable_handlers=self.inheritable_handlers,1441                    parent_run_id=self.parent_run_id,1442                    tags=self.tags,1443                    inheritable_tags=self.inheritable_tags,1444                    metadata=self.metadata,1445                    inheritable_metadata=self.inheritable_metadata,1446                )1447            )14481449        return managers14501451    def on_chain_start(1452        self,1453        serialized: dict[str, Any] | None,1454        inputs: dict[str, Any] | Any,1455        run_id: UUID | None = None,1456        **kwargs: Any,1457    ) -> CallbackManagerForChainRun:1458        """Run when chain starts running.14591460        Args:1461            serialized: The serialized chain.1462            inputs: The inputs to the chain.1463            run_id: The ID of the run.1464            **kwargs: Additional keyword arguments.14651466        Returns:1467            The callback manager for the chain run.14681469        """1470        if run_id is None:1471            run_id = uuid7()1472        handle_event(1473            self.handlers,1474            "on_chain_start",1475            "ignore_chain",1476            serialized,1477            inputs,1478            run_id=run_id,1479            parent_run_id=self.parent_run_id,1480            tags=self.tags,1481            metadata=self.metadata,1482            **kwargs,1483        )14841485        return CallbackManagerForChainRun(1486            run_id=run_id,1487            handlers=self.handlers,1488            inheritable_handlers=self.inheritable_handlers,1489            parent_run_id=self.parent_run_id,1490            tags=self.tags,1491            inheritable_tags=self.inheritable_tags,1492            metadata=self.metadata,1493            inheritable_metadata=self.inheritable_metadata,1494        )14951496    @override1497    def on_tool_start(1498        self,1499        serialized: dict[str, Any] | None,1500        input_str: str,1501        run_id: UUID | None = None,1502        parent_run_id: UUID | None = None,1503        inputs: dict[str, Any] | None = None,1504        **kwargs: Any,1505    ) -> CallbackManagerForToolRun:1506        """Run when tool starts running.15071508        Args:1509            serialized: Serialized representation of the tool.1510            input_str: The  input to the tool as a string.15111512                Non-string inputs are cast to strings.1513            run_id: ID for the run.1514            parent_run_id: The ID of the parent run.1515            inputs: The original input to the tool if provided.15161517                Recommended for usage instead of input_str when the original input is1518                needed.15191520                If provided, the inputs are expected to be formatted as a dict. The keys1521                will correspond to the named-arguments in the tool.1522            **kwargs: The keyword arguments to pass to the event handler15231524        Returns:1525            The callback manager for the tool run.15261527        """1528        if run_id is None:1529            run_id = uuid7()15301531        handle_event(1532            self.handlers,1533            "on_tool_start",1534            "ignore_agent",1535            serialized,1536            input_str,1537            run_id=run_id,1538            parent_run_id=self.parent_run_id,1539            tags=self.tags,1540            metadata=self.metadata,1541            inputs=inputs,1542            **kwargs,1543        )15441545        return CallbackManagerForToolRun(1546            run_id=run_id,1547            handlers=self.handlers,1548            inheritable_handlers=self.inheritable_handlers,1549            parent_run_id=self.parent_run_id,1550            tags=self.tags,1551            inheritable_tags=self.inheritable_tags,1552            metadata=self.metadata,1553            inheritable_metadata=self.inheritable_metadata,1554        )15551556    @override1557    def on_retriever_start(1558        self,1559        serialized: dict[str, Any] | None,1560        query: str,1561        run_id: UUID | None = None,1562        parent_run_id: UUID | None = None,1563        **kwargs: Any,1564    ) -> CallbackManagerForRetrieverRun:1565        """Run when the retriever starts running.15661567        Args:1568            serialized: The serialized retriever.1569            query: The query.1570            run_id: The ID of the run.1571            parent_run_id: The ID of the parent run.1572            **kwargs: Additional keyword arguments.15731574        Returns:1575            The callback manager for the retriever run.1576        """1577        if run_id is None:1578            run_id = uuid7()15791580        handle_event(1581            self.handlers,1582            "on_retriever_start",1583            "ignore_retriever",1584            serialized,1585            query,1586            run_id=run_id,1587            parent_run_id=self.parent_run_id,1588            tags=self.tags,1589            metadata=self.metadata,1590            **kwargs,1591        )15921593        return CallbackManagerForRetrieverRun(1594            run_id=run_id,1595            handlers=self.handlers,1596            inheritable_handlers=self.inheritable_handlers,1597            parent_run_id=self.parent_run_id,1598            tags=self.tags,1599            inheritable_tags=self.inheritable_tags,1600            metadata=self.metadata,1601            inheritable_metadata=self.inheritable_metadata,1602        )16031604    def on_custom_event(1605        self,1606        name: str,1607        data: Any,1608        run_id: UUID | None = None,1609        **kwargs: Any,1610    ) -> None:1611        """Dispatch an adhoc event to the handlers (async version).16121613        This event should NOT be used in any internal LangChain code. The event is meant1614        specifically for users of the library to dispatch custom events that are1615        tailored to their application.16161617        Args:1618            name: The name of the adhoc event.1619            data: The data for the adhoc event.1620            run_id: The ID of the run.16211622        Raises:1623            ValueError: If additional keyword arguments are passed.1624        """1625        if not self.handlers:1626            return1627        if kwargs:1628            msg = (1629                "The dispatcher API does not accept additional keyword arguments."1630                "Please do not pass any additional keyword arguments, instead "1631                "include them in the data field."1632            )1633            raise ValueError(msg)1634        if run_id is None:1635            run_id = uuid7()16361637        handle_event(1638            self.handlers,1639            "on_custom_event",1640            "ignore_custom_event",1641            name,1642            data,1643            run_id=run_id,1644            tags=self.tags,1645            metadata=self.metadata,1646        )16471648    @classmethod1649    def configure(1650        cls,1651        inheritable_callbacks: Callbacks = None,1652        local_callbacks: Callbacks = None,1653        verbose: bool = False,  # noqa: FBT001,FBT0021654        inheritable_tags: list[str] | None = None,1655        local_tags: list[str] | None = None,1656        inheritable_metadata: dict[str, Any] | None = None,1657        local_metadata: dict[str, Any] | None = None,1658        *,1659        langsmith_inheritable_metadata: Mapping[str, Any] | None = None,1660        langsmith_inheritable_tags: list[str] | None = None,1661    ) -> CallbackManager:1662        """Configure the callback manager.16631664        Args:1665            inheritable_callbacks: The inheritable callbacks.1666            local_callbacks: The local callbacks.1667            verbose: Whether to enable verbose mode.1668            inheritable_tags: The inheritable tags.1669            local_tags: The local tags.1670            inheritable_metadata: The inheritable metadata.1671            local_metadata: The local metadata.1672            langsmith_inheritable_metadata: Default inheritable metadata applied1673                to any `LangChainTracer` handlers via `set_defaults`.1674            langsmith_inheritable_tags: Default inheritable tags applied to any1675                `LangChainTracer` handlers via `set_defaults`.16761677        Returns:1678            The configured callback manager.1679        """1680        return _configure(1681            cls,1682            inheritable_callbacks,1683            local_callbacks,1684            inheritable_tags,1685            local_tags,1686            inheritable_metadata,1687            local_metadata,1688            verbose=verbose,1689            langsmith_inheritable_metadata=langsmith_inheritable_metadata,1690            langsmith_inheritable_tags=langsmith_inheritable_tags,1691        )169216931694class CallbackManagerForChainGroup(CallbackManager):1695    """Callback manager for the chain group."""16961697    def __init__(1698        self,1699        handlers: list[BaseCallbackHandler],1700        inheritable_handlers: list[BaseCallbackHandler] | None = None,1701        parent_run_id: UUID | None = None,1702        *,1703        parent_run_manager: CallbackManagerForChainRun,1704        **kwargs: Any,1705    ) -> None:1706        """Initialize the callback manager.17071708        Args:1709            handlers: The list of handlers.1710            inheritable_handlers: The list of inheritable handlers.1711            parent_run_id: The ID of the parent run.1712            parent_run_manager: The parent run manager.1713            **kwargs: Additional keyword arguments.17141715        """1716        super().__init__(1717            handlers,1718            inheritable_handlers,1719            parent_run_id,1720            **kwargs,1721        )1722        self.parent_run_manager = parent_run_manager1723        self.ended = False17241725    @override1726    def copy(self) -> CallbackManagerForChainGroup:1727        return self.__class__(1728            handlers=self.handlers.copy(),1729            inheritable_handlers=self.inheritable_handlers.copy(),1730            parent_run_id=self.parent_run_id,1731            tags=self.tags.copy(),1732            inheritable_tags=self.inheritable_tags.copy(),1733            metadata=self.metadata.copy(),1734            inheritable_metadata=self.inheritable_metadata.copy(),1735            parent_run_manager=self.parent_run_manager,1736        )17371738    def merge(1739        self: CallbackManagerForChainGroup, other: BaseCallbackManager1740    ) -> CallbackManagerForChainGroup:1741        """Merge the group callback manager with another callback manager.17421743        Overwrites the merge method in the base class to ensure that the parent run1744        manager is preserved. Keeps the `parent_run_manager` from the current object.17451746        Returns:1747            A copy of the current object with the handlers, tags, and other attributes1748            merged from the other object.17491750        Example:1751            ```python1752            # Merging two callback managers1753            from langchain_core.callbacks.manager import (1754                CallbackManager,1755                trace_as_chain_group,1756            )1757            from langchain_core.callbacks.stdout import StdOutCallbackHandler17581759            manager = CallbackManager(handlers=[StdOutCallbackHandler()], tags=["tag2"])1760            with trace_as_chain_group("My Group Name", tags=["tag1"]) as group_manager:1761                merged_manager = group_manager.merge(manager)1762                print(type(merged_manager))1763                # <class 'langchain_core.callbacks.manager.CallbackManagerForChainGroup'>17641765                print(merged_manager.handlers)1766                # [1767                #    <langchain_core.callbacks.stdout.LangChainTracer object at ...>,1768                #    <langchain_core.callbacks.streaming_stdout.StdOutCallbackHandler object at ...>,1769                # ]17701771                print(merged_manager.tags)1772                #    ['tag2', 'tag1']1773            ```1774        """  # noqa: E5011775        manager = self.__class__(1776            parent_run_id=self.parent_run_id or other.parent_run_id,1777            handlers=[],1778            inheritable_handlers=[],1779            tags=list(set(self.tags + other.tags)),1780            inheritable_tags=list(set(self.inheritable_tags + other.inheritable_tags)),1781            metadata={1782                **self.metadata,1783                **other.metadata,1784            },1785            parent_run_manager=self.parent_run_manager,1786        )17871788        handlers = self.handlers + other.handlers1789        inheritable_handlers = self.inheritable_handlers + other.inheritable_handlers17901791        for handler in handlers:1792            manager.add_handler(handler)17931794        for handler in inheritable_handlers:1795            manager.add_handler(handler, inherit=True)1796        return manager17971798    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1799        """Run when traced chain group ends.18001801        Args:1802            outputs: The outputs of the chain.1803            **kwargs: Additional keyword arguments.18041805        """1806        self.ended = True1807        return self.parent_run_manager.on_chain_end(outputs, **kwargs)18081809    def on_chain_error(1810        self,1811        error: BaseException,1812        **kwargs: Any,1813    ) -> None:1814        """Run when chain errors.18151816        Args:1817            error: The error.1818            **kwargs: Additional keyword arguments.18191820        """1821        self.ended = True1822        return self.parent_run_manager.on_chain_error(error, **kwargs)182318241825class AsyncCallbackManager(BaseCallbackManager):1826    """Async callback manager that handles callbacks from LangChain."""18271828    @property1829    def is_async(self) -> bool:1830        """Return whether the handler is async."""1831        return True18321833    async def on_llm_start(1834        self,1835        serialized: dict[str, Any],1836        prompts: list[str],1837        run_id: UUID | None = None,1838        **kwargs: Any,1839    ) -> list[AsyncCallbackManagerForLLMRun]:1840        """Run when LLM starts running.18411842        Args:1843            serialized: The serialized LLM.1844            prompts: The list of prompts.1845            run_id: The ID of the run.1846            **kwargs: Additional keyword arguments.18471848        Returns:1849            The list of async callback managers, one for each LLM run corresponding to1850            each prompt.1851        """1852        inline_tasks = []1853        non_inline_tasks = []1854        inline_handlers = [handler for handler in self.handlers if handler.run_inline]1855        non_inline_handlers = [1856            handler for handler in self.handlers if not handler.run_inline1857        ]1858        managers = []18591860        for prompt in prompts:1861            if run_id is not None:1862                run_id_ = run_id1863                run_id = None1864            else:1865                run_id_ = uuid7()18661867            if inline_handlers:1868                inline_tasks.append(1869                    ahandle_event(1870                        inline_handlers,1871                        "on_llm_start",1872                        "ignore_llm",1873                        serialized,1874                        [prompt],1875                        run_id=run_id_,1876                        parent_run_id=self.parent_run_id,1877                        tags=self.tags,1878                        metadata=self.metadata,1879                        **kwargs,1880                    )1881                )1882            else:1883                non_inline_tasks.append(1884                    ahandle_event(1885                        non_inline_handlers,1886                        "on_llm_start",1887                        "ignore_llm",1888                        serialized,1889                        [prompt],1890                        run_id=run_id_,1891                        parent_run_id=self.parent_run_id,1892                        tags=self.tags,1893                        metadata=self.metadata,1894                        **kwargs,1895                    )1896                )18971898            managers.append(1899                AsyncCallbackManagerForLLMRun(1900                    run_id=run_id_,1901                    handlers=self.handlers,1902                    inheritable_handlers=self.inheritable_handlers,1903                    parent_run_id=self.parent_run_id,1904                    tags=self.tags,1905                    inheritable_tags=self.inheritable_tags,1906                    metadata=self.metadata,1907                    inheritable_metadata=self.inheritable_metadata,1908                )1909            )19101911        # Run inline tasks sequentially1912        for inline_task in inline_tasks:1913            await inline_task19141915        # Run non-inline tasks concurrently1916        if non_inline_tasks:1917            await asyncio.gather(*non_inline_tasks)19181919        return managers19201921    async def on_chat_model_start(1922        self,1923        serialized: dict[str, Any],1924        messages: list[list[BaseMessage]],1925        run_id: UUID | None = None,1926        **kwargs: Any,1927    ) -> list[AsyncCallbackManagerForLLMRun]:1928        """Async run when LLM starts running.19291930        Args:1931            serialized: The serialized LLM.1932            messages: The list of messages.1933            run_id: The ID of the run.1934            **kwargs: Additional keyword arguments.19351936        Returns:1937            The list of async callback managers, one for each LLM run corresponding to1938            each inner message list.1939        """1940        inline_tasks = []1941        non_inline_tasks = []1942        managers = []19431944        for message_list in messages:1945            if run_id is not None:1946                run_id_ = run_id1947                run_id = None1948            else:1949                run_id_ = uuid7()19501951            for handler in self.handlers:1952                task = ahandle_event(1953                    [handler],1954                    "on_chat_model_start",1955                    "ignore_chat_model",1956                    serialized,1957                    [message_list],1958                    run_id=run_id_,1959                    parent_run_id=self.parent_run_id,1960                    tags=self.tags,1961                    metadata=self.metadata,1962                    **kwargs,1963                )1964                if handler.run_inline:1965                    inline_tasks.append(task)1966                else:1967                    non_inline_tasks.append(task)19681969            managers.append(1970                AsyncCallbackManagerForLLMRun(1971                    run_id=run_id_,1972                    handlers=self.handlers,1973                    inheritable_handlers=self.inheritable_handlers,1974                    parent_run_id=self.parent_run_id,1975                    tags=self.tags,1976                    inheritable_tags=self.inheritable_tags,1977                    metadata=self.metadata,1978                    inheritable_metadata=self.inheritable_metadata,1979                )1980            )19811982        # Run inline tasks sequentially1983        for task in inline_tasks:1984            await task19851986        # Run non-inline tasks concurrently1987        if non_inline_tasks:1988            await asyncio.gather(*non_inline_tasks)19891990        return managers19911992    async def on_chain_start(1993        self,1994        serialized: dict[str, Any] | None,1995        inputs: dict[str, Any] | Any,1996        run_id: UUID | None = None,1997        **kwargs: Any,1998    ) -> AsyncCallbackManagerForChainRun:1999        """Async run when chain starts running.

Code quality findings 72

Ensure functions have docstrings for documentation
missing-docstring
def trace_as_chain_group(
Ensure functions have docstrings for documentation
missing-docstring
async def atrace_as_chain_group(
Ensure functions have docstrings for documentation
missing-docstring
async def wrapped(*args: Any, **kwargs: Any) -> Any:
Ensure functions have docstrings for documentation
missing-docstring
def handle_event(
Ensure try blocks have corresponding except or finally blocks
try-without-except
try:
Ensure functions have docstrings for documentation
missing-docstring
async def ahandle_event(
Ensure functions have docstrings for documentation
missing-docstring
def on_text(
Ensure functions have docstrings for documentation
missing-docstring
def on_retry(
Ensure functions have docstrings for documentation
missing-docstring
async def on_text(
Ensure functions have docstrings for documentation
missing-docstring
async def on_retry(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_new_token(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_llm_new_token(
Ensure functions have docstrings for documentation
missing-docstring
async def on_llm_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_chain_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_tool_end(
Ensure functions have docstrings for documentation
missing-docstring
def on_tool_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_tool_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_end(
Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_retriever_end(
Ensure functions have docstrings for documentation
missing-docstring
async def on_retriever_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_chat_model_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_chain_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_tool_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_custom_event(
Ensure functions have docstrings for documentation
missing-docstring
def configure(
Ensure functions have docstrings for documentation
missing-docstring
def copy(self) -> CallbackManagerForChainGroup:
Ensure functions have docstrings for documentation
missing-docstring
def merge(
Use logging module for better control and configurability
print-statement
print(type(merged_manager))
Use logging module for better control and configurability
print-statement
print(merged_manager.handlers)
Use logging module for better control and configurability
print-statement
print(merged_manager.tags)
Ensure functions have docstrings for documentation
missing-docstring
def on_chain_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_llm_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chat_model_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_tool_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_custom_event(
Ensure functions have docstrings for documentation
missing-docstring
async def on_retriever_start(
Ensure functions have docstrings for documentation
missing-docstring
def configure(
Ensure functions have docstrings for documentation
missing-docstring
def merge(
Use logging module for better control and configurability
print-statement
print(type(merged_manager))
Use logging module for better control and configurability
print-statement
print(merged_manager.handlers)
Use logging module for better control and configurability
print-statement
print(merged_manager.tags)
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_error(
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(inheritable_callbacks, list) or inheritable_callbacks is None:
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(local_callbacks, list)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
isinstance(handler, StdOutCallbackHandler)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
isinstance(handler, ConsoleCallbackHandler)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
isinstance(handler, LangChainTracer)
Ensure try blocks have corresponding except or finally blocks
try-without-except
try:
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(handler, LangChainTracer):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
isinstance(handler, handler_class)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(handler, LangChainTracer)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(handler, LangChainTracer)
Ensure functions have docstrings for documentation
missing-docstring
async def adispatch_custom_event(
Ensure functions have docstrings for documentation
missing-docstring
async def on_custom_event(
Use logging module for better control and configurability
print-statement
print(f"Received custom event: {name} with data: {data}")
Ensure functions have docstrings for documentation
missing-docstring
async def foo(inputs):
Ensure functions have docstrings for documentation
missing-docstring
async def on_custom_event(
Use logging module for better control and configurability
print-statement
print(f"Received custom event: {name} with data: {data}")
Ensure functions have docstrings for documentation
missing-docstring
async def foo(inputs):
Use logging module for better control and configurability
print-statement
print(event)
Ensure functions have docstrings for documentation
missing-docstring
def dispatch_custom_event(
Ensure functions have docstrings for documentation
missing-docstring
def on_custom_event(
Use logging module for better control and configurability
print-statement
print(f"Received custom event: {name} with data: {data}")
Ensure functions have docstrings for documentation
missing-docstring
def foo(inputs):
Avoid complex 'lambda' functions; prefer named functions for clarity and debugging
info maintainability complex-lambda
# within a tool or a lambda and have the metadata events associated
Avoid complex 'lambda' functions; prefer named functions for clarity and debugging
info maintainability complex-lambda
# within a tool or a lambda and have the metadata events associated

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.