libs/core/langchain_core/callbacks/manager.py PYTHON 2,827 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,827.
1"""Run managers."""23from __future__ import annotations45import asyncio6import atexit7import functools8import inspect9import logging10from abc import ABC, abstractmethod11from collections.abc import Callable, Mapping12from concurrent.futures import ThreadPoolExecutor13from contextlib import asynccontextmanager, contextmanager14from contextvars import copy_context15from typing import TYPE_CHECKING, Any, TypeVar, cast1617from typing_extensions import Self, override1819from langchain_core.callbacks.base import (20    BaseCallbackHandler,21    BaseCallbackManager,22    Callbacks,23    ChainManagerMixin,24    LLMManagerMixin,25    RetrieverManagerMixin,26    RunManagerMixin,27    ToolManagerMixin,28)29from langchain_core.callbacks.stdout import StdOutCallbackHandler30from langchain_core.globals import get_debug31from langchain_core.messages import BaseMessage, get_buffer_string32from langchain_core.utils.env import env_var_is_set33from langchain_core.utils.uuid import uuid73435if TYPE_CHECKING:36    from collections.abc import AsyncGenerator, Coroutine, Generator, Sequence37    from uuid import UUID3839    from langchain_protocol.protocol import MessagesData40    from tenacity import RetryCallState4142    from langchain_core.agents import AgentAction, AgentFinish43    from langchain_core.documents import Document44    from langchain_core.outputs import ChatGenerationChunk, GenerationChunk, LLMResult45    from langchain_core.runnables.config import RunnableConfig46    from langchain_core.tracers.schemas import Run4748logger = logging.getLogger(__name__)495051def _get_debug() -> bool:52    return get_debug()535455@contextmanager56def trace_as_chain_group(57    group_name: str,58    callback_manager: CallbackManager | None = None,59    *,60    inputs: dict[str, Any] | None = None,61    project_name: str | None = None,62    example_id: str | UUID | None = None,63    run_id: UUID | None = None,64    tags: list[str] | None = None,65    metadata: dict[str, Any] | None = None,66) -> Generator[CallbackManagerForChainGroup, None, None]:67    """Get a callback manager for a chain group in a context manager.6869    Useful for grouping different calls together as a single run even if they aren't70    composed in a single chain.7172    Args:73        group_name: The name of the chain group.74        callback_manager: The callback manager to use.75        inputs: The inputs to the chain group.76        project_name: The name of the project.77        example_id: The ID of the example.78        run_id: The ID of the run.79        tags: The inheritable tags to apply to all runs.80        metadata: The metadata to apply to all runs.8182    !!! note8384        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in85        LangSmith.8687    Yields:88        The callback manager for the chain group.8990    Example:91        ```python92        llm_input = "Foo"93        with trace_as_chain_group("group_name", inputs={"input": llm_input}) as manager:94            # Use the callback manager for the chain group95            res = llm.invoke(llm_input, {"callbacks": manager})96            manager.on_chain_end({"output": res})97        ```98    """99    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level100        _get_trace_callbacks,101    )102103    cb = _get_trace_callbacks(104        project_name, example_id, callback_manager=callback_manager105    )106    cm = CallbackManager.configure(107        inheritable_callbacks=cb,108        inheritable_tags=tags,109        inheritable_metadata=metadata,110    )111112    run_manager = cm.on_chain_start({"name": group_name}, inputs or {}, run_id=run_id)113    child_cm = run_manager.get_child()114    group_cm = CallbackManagerForChainGroup(115        child_cm.handlers,116        child_cm.inheritable_handlers,117        child_cm.parent_run_id,118        parent_run_manager=run_manager,119        tags=child_cm.tags,120        inheritable_tags=child_cm.inheritable_tags,121        metadata=child_cm.metadata,122        inheritable_metadata=child_cm.inheritable_metadata,123    )124    try:125        yield group_cm126    except Exception as e:127        if not group_cm.ended:128            run_manager.on_chain_error(e)129        raise130    else:131        if not group_cm.ended:132            run_manager.on_chain_end({})133134135@asynccontextmanager136async def atrace_as_chain_group(137    group_name: str,138    callback_manager: AsyncCallbackManager | None = None,139    *,140    inputs: dict[str, Any] | None = None,141    project_name: str | None = None,142    example_id: str | UUID | None = None,143    run_id: UUID | None = None,144    tags: list[str] | None = None,145    metadata: dict[str, Any] | None = None,146) -> AsyncGenerator[AsyncCallbackManagerForChainGroup, None]:147    """Get an async callback manager for a chain group in a context manager.148149    Useful for grouping different async calls together as a single run even if they150    aren't composed in a single chain.151152    Args:153        group_name: The name of the chain group.154        callback_manager: The async callback manager to use, which manages tracing and155            other callback behavior.156        inputs: The inputs to the chain group.157        project_name: The name of the project.158        example_id: The ID of the example.159        run_id: The ID of the run.160        tags: The inheritable tags to apply to all runs.161        metadata: The metadata to apply to all runs.162163    Yields:164        The async callback manager for the chain group.165166    !!! note167168        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in169        LangSmith.170171    Example:172        ```python173        llm_input = "Foo"174        async with atrace_as_chain_group(175            "group_name", inputs={"input": llm_input}176        ) as manager:177            # Use the async callback manager for the chain group178            res = await llm.ainvoke(llm_input, {"callbacks": manager})179            await manager.on_chain_end({"output": res})180        ```181    """182    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level183        _get_trace_callbacks,184    )185186    cb = _get_trace_callbacks(187        project_name, example_id, callback_manager=callback_manager188    )189    cm = AsyncCallbackManager.configure(190        inheritable_callbacks=cb, inheritable_tags=tags, inheritable_metadata=metadata191    )192193    run_manager = await cm.on_chain_start(194        {"name": group_name}, inputs or {}, run_id=run_id195    )196    child_cm = run_manager.get_child()197    group_cm = AsyncCallbackManagerForChainGroup(198        child_cm.handlers,199        child_cm.inheritable_handlers,200        child_cm.parent_run_id,201        parent_run_manager=run_manager,202        tags=child_cm.tags,203        inheritable_tags=child_cm.inheritable_tags,204        metadata=child_cm.metadata,205        inheritable_metadata=child_cm.inheritable_metadata,206    )207    try:208        yield group_cm209    except Exception as e:210        if not group_cm.ended:211            await run_manager.on_chain_error(e)212        raise213    else:214        if not group_cm.ended:215            await run_manager.on_chain_end({})216217218Func = TypeVar("Func", bound=Callable[..., Any])219220221def shielded(func: Func) -> Func:222    """Makes so an awaitable method is always shielded from cancellation.223224    Args:225        func: The function to shield.226227    Returns:228        The shielded function229230    """231232    @functools.wraps(func)233    async def wrapped(*args: Any, **kwargs: Any) -> Any:234        # Capture the current context to preserve context variables235        ctx = copy_context()236237        # Create the coroutine238        coro = func(*args, **kwargs)239240        # For Python 3.11+, create task with explicit context241        # For older versions, fallback to original behavior242        try:243            # Create a task with the captured context to preserve context variables244            task = asyncio.create_task(coro, context=ctx)  # type: ignore[call-arg, unused-ignore]245            # `call-arg` used to not fail 3.9 or 3.10 tests246            return await asyncio.shield(task)247        except TypeError:248            # Python < 3.11 fallback - create task normally then shield249            # This won't preserve context perfectly but is better than nothing250            task = asyncio.create_task(coro)251            return await asyncio.shield(task)252253    return cast("Func", wrapped)254255256async def _achat_model_start_fallback(257    coro: Coroutine[Any, Any, Any],258    handler: BaseCallbackHandler,259    *args: Any,260    **kwargs: Any,261) -> None:262    """Wrap an async `on_chat_model_start` coroutine with fallback.263264    Catches `NotImplementedError` and triggers the `on_llm_start` fallback.265    This covers async handlers invoked from a **sync** `handle_event` call,266    where the coroutine is collected into `coros` and executed later by267    `_run_coros`. Without this wrapper the `NotImplementedError` would be268    caught generically by `_run_coros` and the trace would be lost.269    """270    try:271        await coro272    except NotImplementedError:273        message_strings = [get_buffer_string(m) for m in args[1]]274        await _ahandle_event_for_handler(275            handler,276            "on_llm_start",277            "ignore_llm",278            args[0],279            message_strings,280            *args[2:],281            **kwargs,282        )283284285def handle_event(286    handlers: list[BaseCallbackHandler],287    event_name: str,288    ignore_condition_name: str | None,289    *args: Any,290    **kwargs: Any,291) -> None:292    """Generic event handler for `CallbackManager`.293294    Args:295        handlers: The list of handlers that will handle the event.296        event_name: The name of the event (e.g., `'on_llm_start'`).297        ignore_condition_name: Name of the attribute defined on handler that if `True`298            will cause the handler to be skipped for the given event.299        *args: The arguments to pass to the event handler.300        **kwargs: The keyword arguments to pass to the event handler301302    """303    coros: list[Coroutine[Any, Any, Any]] = []304305    try:306        message_strings: list[str] | None = None307        for handler in handlers:308            try:309                if ignore_condition_name is None or not getattr(310                    handler, ignore_condition_name311                ):312                    event = getattr(handler, event_name)(*args, **kwargs)313                    if asyncio.iscoroutine(event):314                        if event_name == "on_chat_model_start":315                            event = _achat_model_start_fallback(316                                event, handler, *args, **kwargs317                            )318                        coros.append(event)319            except NotImplementedError as e:320                if event_name == "on_chat_model_start":321                    if message_strings is None:322                        message_strings = [get_buffer_string(m) for m in args[1]]323                    handle_event(324                        [handler],325                        "on_llm_start",326                        "ignore_llm",327                        args[0],328                        message_strings,329                        *args[2:],330                        **kwargs,331                    )332                else:333                    handler_name = handler.__class__.__name__334                    logger.warning(335                        "NotImplementedError in %s.%s callback: %s",336                        handler_name,337                        event_name,338                        repr(e),339                    )340            except Exception as e:341                logger.warning(342                    "Error in %s.%s callback: %s",343                    handler.__class__.__name__,344                    event_name,345                    repr(e),346                )347                if handler.raise_error:348                    raise349    finally:350        if coros:351            try:352                # Raises RuntimeError if there is no current event loop.353                asyncio.get_running_loop()354                loop_running = True355            except RuntimeError:356                loop_running = False357358            if loop_running:359                # If we try to submit this coroutine to the running loop360                # we end up in a deadlock, as we'd have gotten here from a361                # running coroutine, which we cannot interrupt to run this one.362                # The solution is to run the synchronous function on the globally shared363                # thread pool executor to avoid blocking the main event loop.364                _executor().submit(copy_context().run, _run_coros, coros).result()365            else:366                # If there's no running loop, we can run the coroutines directly.367                _run_coros(coros)368369370def _run_coros(coros: list[Coroutine[Any, Any, Any]]) -> None:371    # Note: exceptions raised by these coroutines are always logged and swallowed372    # here, regardless of the handler's `raise_error` setting. Async-handler errors373    # driven through sync `handle_event` therefore never propagate, unlike errors374    # from sync handlers (which honor `raise_error`). This is a pre-existing375    # asymmetry between the sync and async callback paths.376    if hasattr(asyncio, "Runner"):377        # Python 3.11+378        # Run the coroutines in a new event loop, taking care to379        # - install signal handlers380        # - run pending tasks scheduled by `coros`381        # - close asyncgens and executors382        # - close the loop383        with asyncio.Runner() as runner:384            # Run the coroutine, get the result385            for coro in coros:386                try:387                    runner.run(coro)388                except Exception as e:389                    logger.warning("Error in callback coroutine: %s", repr(e))390391            # Run pending tasks scheduled by coros until they are all done392            while pending := asyncio.all_tasks(runner.get_loop()):393                runner.run(asyncio.wait(pending))394    else:395        # Before Python 3.11 we need to run each coroutine in a new event loop396        # as the Runner api is not available.397        for coro in coros:398            try:399                asyncio.run(coro)400            except Exception as e:401                logger.warning("Error in callback coroutine: %s", repr(e))402403404async def _ahandle_event_for_handler(405    handler: BaseCallbackHandler,406    event_name: str,407    ignore_condition_name: str | None,408    *args: Any,409    **kwargs: Any,410) -> None:411    try:412        if ignore_condition_name is None or not getattr(handler, ignore_condition_name):413            event = getattr(handler, event_name)414            if inspect.iscoroutinefunction(event):415                await event(*args, **kwargs)416            elif handler.run_inline:417                event(*args, **kwargs)418            else:419                await asyncio.get_event_loop().run_in_executor(420                    None,421                    functools.partial(copy_context().run, event, *args, **kwargs),422                )423    except NotImplementedError as e:424        if event_name == "on_chat_model_start":425            message_strings = [get_buffer_string(m) for m in args[1]]426            await _ahandle_event_for_handler(427                handler,428                "on_llm_start",429                "ignore_llm",430                args[0],431                message_strings,432                *args[2:],433                **kwargs,434            )435        else:436            logger.warning(437                "NotImplementedError in %s.%s callback: %s",438                handler.__class__.__name__,439                event_name,440                repr(e),441            )442    except Exception as e:443        logger.warning(444            "Error in %s.%s callback: %s",445            handler.__class__.__name__,446            event_name,447            repr(e),448        )449        if handler.raise_error:450            raise451452453async def ahandle_event(454    handlers: list[BaseCallbackHandler],455    event_name: str,456    ignore_condition_name: str | None,457    *args: Any,458    **kwargs: Any,459) -> None:460    """Async generic event handler for `AsyncCallbackManager`.461462    Args:463        handlers: The list of handlers that will handle the event.464        event_name: The name of the event (e.g., `'on_llm_start'`).465        ignore_condition_name: Name of the attribute defined on handler that if `True`466            will cause the handler to be skipped for the given event.467        *args: The arguments to pass to the event handler.468        **kwargs: The keyword arguments to pass to the event handler.469470    """471    for handler in [h for h in handlers if h.run_inline]:472        await _ahandle_event_for_handler(473            handler, event_name, ignore_condition_name, *args, **kwargs474        )475    await asyncio.gather(476        *(477            _ahandle_event_for_handler(478                handler,479                event_name,480                ignore_condition_name,481                *args,482                **kwargs,483            )484            for handler in handlers485            if not handler.run_inline486        )487    )488489490class BaseRunManager(RunManagerMixin):491    """Base class for run manager (a bound callback manager)."""492493    def __init__(494        self,495        *,496        run_id: UUID,497        handlers: list[BaseCallbackHandler],498        inheritable_handlers: list[BaseCallbackHandler],499        parent_run_id: UUID | None = None,500        tags: list[str] | None = None,501        inheritable_tags: list[str] | None = None,502        metadata: dict[str, Any] | None = None,503        inheritable_metadata: dict[str, Any] | None = None,504    ) -> None:505        """Initialize the run manager.506507        Args:508            run_id: The ID of the run.509            handlers: The list of handlers.510            inheritable_handlers: The list of inheritable handlers.511            parent_run_id: The ID of the parent run.512            tags: The list of tags.513            inheritable_tags: The list of inheritable tags.514            metadata: The metadata.515            inheritable_metadata: The inheritable metadata.516517        """518        self.run_id = run_id519        self.handlers = handlers520        self.inheritable_handlers = inheritable_handlers521        self.parent_run_id = parent_run_id522        self.tags = tags or []523        self.inheritable_tags = inheritable_tags or []524        self.metadata = metadata or {}525        self.inheritable_metadata = inheritable_metadata or {}526527    @classmethod528    def get_noop_manager(cls) -> Self:529        """Return a manager that doesn't perform any operations.530531        Returns:532            The noop manager.533534        """535        return cls(536            run_id=uuid7(),537            handlers=[],538            inheritable_handlers=[],539            tags=[],540            inheritable_tags=[],541            metadata={},542            inheritable_metadata={},543        )544545546class RunManager(BaseRunManager):547    """Synchronous run manager."""548549    def on_text(550        self,551        text: str,552        **kwargs: Any,553    ) -> None:554        """Run when a text is received.555556        Args:557            text: The received text.558            **kwargs: Additional keyword arguments.559        """560        if not self.handlers:561            return562        handle_event(563            self.handlers,564            "on_text",565            None,566            text,567            run_id=self.run_id,568            parent_run_id=self.parent_run_id,569            tags=self.tags,570            **kwargs,571        )572573    def on_retry(574        self,575        retry_state: RetryCallState,576        **kwargs: Any,577    ) -> None:578        """Run when a retry is received.579580        Args:581            retry_state: The retry state.582            **kwargs: Additional keyword arguments.583584        """585        if not self.handlers:586            return587        handle_event(588            self.handlers,589            "on_retry",590            "ignore_retry",591            retry_state,592            run_id=self.run_id,593            parent_run_id=self.parent_run_id,594            tags=self.tags,595            **kwargs,596        )597598599class ParentRunManager(RunManager):600    """Synchronous parent run manager."""601602    def get_child(self, tag: str | None = None) -> CallbackManager:603        """Get a child callback manager.604605        Args:606            tag: The tag for the child callback manager.607608        Returns:609            The child callback manager.610611        """612        manager = CallbackManager(handlers=[], parent_run_id=self.run_id)613        manager.set_handlers(self.inheritable_handlers)614        manager.add_tags(self.inheritable_tags)615        manager.add_metadata(self.inheritable_metadata)616        if tag is not None:617            manager.add_tags([tag], inherit=False)618        return manager619620621class AsyncRunManager(BaseRunManager, ABC):622    """Async run manager."""623624    @abstractmethod625    def get_sync(self) -> RunManager:626        """Get the equivalent sync `RunManager`.627628        Returns:629            The sync `RunManager`.630631        """632633    async def on_text(634        self,635        text: str,636        **kwargs: Any,637    ) -> None:638        """Run when a text is received.639640        Args:641            text: The received text.642            **kwargs: Additional keyword arguments.643        """644        if not self.handlers:645            return646        await ahandle_event(647            self.handlers,648            "on_text",649            None,650            text,651            run_id=self.run_id,652            parent_run_id=self.parent_run_id,653            tags=self.tags,654            **kwargs,655        )656657    async def on_retry(658        self,659        retry_state: RetryCallState,660        **kwargs: Any,661    ) -> None:662        """Async run when a retry is received.663664        Args:665            retry_state: The retry state.666            **kwargs: Additional keyword arguments.667668        """669        if not self.handlers:670            return671        await ahandle_event(672            self.handlers,673            "on_retry",674            "ignore_retry",675            retry_state,676            run_id=self.run_id,677            parent_run_id=self.parent_run_id,678            tags=self.tags,679            **kwargs,680        )681682683class AsyncParentRunManager(AsyncRunManager):684    """Async parent run manager."""685686    def get_child(self, tag: str | None = None) -> AsyncCallbackManager:687        """Get a child callback manager.688689        Args:690            tag: The tag for the child callback manager.691692        Returns:693            The child callback manager.694695        """696        manager = AsyncCallbackManager(handlers=[], parent_run_id=self.run_id)697        manager.set_handlers(self.inheritable_handlers)698        manager.add_tags(self.inheritable_tags)699        manager.add_metadata(self.inheritable_metadata)700        if tag is not None:701            manager.add_tags([tag], inherit=False)702        return manager703704705class CallbackManagerForLLMRun(RunManager, LLMManagerMixin):706    """Callback manager for LLM run."""707708    def on_llm_new_token(709        self,710        token: str | list[str | dict[str, Any]],711        *,712        chunk: GenerationChunk | ChatGenerationChunk | None = None,713        **kwargs: Any,714    ) -> None:715        """Run when LLM generates a new token.716717        Args:718            token: The new token, or a list of content blocks.719            chunk: The chunk.720            **kwargs: Additional keyword arguments.721722        """723        if not self.handlers:724            return725        handle_event(726            self.handlers,727            "on_llm_new_token",728            "ignore_llm",729            token=token,730            run_id=self.run_id,731            parent_run_id=self.parent_run_id,732            tags=self.tags,733            chunk=chunk,734            **kwargs,735        )736737    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:738        """Run when LLM ends running.739740        Args:741            response: The LLM result.742            **kwargs: Additional keyword arguments.743744        """745        if not self.handlers:746            return747        handle_event(748            self.handlers,749            "on_llm_end",750            "ignore_llm",751            response,752            run_id=self.run_id,753            parent_run_id=self.parent_run_id,754            tags=self.tags,755            **kwargs,756        )757758    def on_llm_error(759        self,760        error: BaseException,761        **kwargs: Any,762    ) -> None:763        """Run when LLM errors.764765        Args:766            error: The error.767            **kwargs: Additional keyword arguments.768769                - response (LLMResult): The response which was generated before770                    the error occurred.771        """772        if not self.handlers:773            return774        handle_event(775            self.handlers,776            "on_llm_error",777            "ignore_llm",778            error,779            run_id=self.run_id,780            parent_run_id=self.parent_run_id,781            tags=self.tags,782            **kwargs,783        )784785    def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:786        """Run on each protocol event from `stream_events(version="v3")`.787788        Args:789            event: The protocol event.790            **kwargs: Additional keyword arguments.791        """792        if not self.handlers:793            return794        handle_event(795            self.handlers,796            "on_stream_event",797            "ignore_llm",798            event,799            run_id=self.run_id,800            parent_run_id=self.parent_run_id,801            tags=self.tags,802            **kwargs,803        )804805806class AsyncCallbackManagerForLLMRun(AsyncRunManager, LLMManagerMixin):807    """Async callback manager for LLM run."""808809    def get_sync(self) -> CallbackManagerForLLMRun:810        """Get the equivalent sync `RunManager`.811812        Returns:813            The sync `RunManager`.814815        """816        return CallbackManagerForLLMRun(817            run_id=self.run_id,818            handlers=self.handlers,819            inheritable_handlers=self.inheritable_handlers,820            parent_run_id=self.parent_run_id,821            tags=self.tags,822            inheritable_tags=self.inheritable_tags,823            metadata=self.metadata,824            inheritable_metadata=self.inheritable_metadata,825        )826827    async def on_llm_new_token(828        self,829        token: str | list[str | dict[str, Any]],830        *,831        chunk: GenerationChunk | ChatGenerationChunk | None = None,832        **kwargs: Any,833    ) -> None:834        """Run when LLM generates a new token.835836        Args:837            token: The new token, or a list of content blocks.838            chunk: The chunk.839            **kwargs: Additional keyword arguments.840841        """842        if not self.handlers:843            return844        await ahandle_event(845            self.handlers,846            "on_llm_new_token",847            "ignore_llm",848            token,849            chunk=chunk,850            run_id=self.run_id,851            parent_run_id=self.parent_run_id,852            tags=self.tags,853            **kwargs,854        )855856    @shielded857    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:858        """Run when LLM ends running.859860        Args:861            response: The LLM result.862            **kwargs: Additional keyword arguments.863864        """865        if not self.handlers:866            return867        await ahandle_event(868            self.handlers,869            "on_llm_end",870            "ignore_llm",871            response,872            run_id=self.run_id,873            parent_run_id=self.parent_run_id,874            tags=self.tags,875            **kwargs,876        )877878    @shielded879    async def on_llm_error(880        self,881        error: BaseException,882        **kwargs: Any,883    ) -> None:884        """Run when LLM errors.885886        Args:887            error: The error.888            **kwargs: Additional keyword arguments.889890                - response (LLMResult): The response which was generated before891                    the error occurred.892893        """894        if not self.handlers:895            return896        await ahandle_event(897            self.handlers,898            "on_llm_error",899            "ignore_llm",900            error,901            run_id=self.run_id,902            parent_run_id=self.parent_run_id,903            tags=self.tags,904            **kwargs,905        )906907    async def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:908        """Run on each protocol event from `astream_events(version="v3")`.909910        Args:911            event: The protocol event.912            **kwargs: Additional keyword arguments.913        """914        if not self.handlers:915            return916        await ahandle_event(917            self.handlers,918            "on_stream_event",919            "ignore_llm",920            event,921            run_id=self.run_id,922            parent_run_id=self.parent_run_id,923            tags=self.tags,924            **kwargs,925        )926927928class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):929    """Callback manager for chain run."""930931    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:932        """Run when chain ends running.933934        Args:935            outputs: The outputs of the chain.936            **kwargs: Additional keyword arguments.937938        """939        if not self.handlers:940            return941        handle_event(942            self.handlers,943            "on_chain_end",944            "ignore_chain",945            outputs,946            run_id=self.run_id,947            parent_run_id=self.parent_run_id,948            tags=self.tags,949            **kwargs,950        )951952    def on_chain_error(953        self,954        error: BaseException,955        **kwargs: Any,956    ) -> None:957        """Run when chain errors.958959        Args:960            error: The error.961            **kwargs: Additional keyword arguments.962963        """964        if not self.handlers:965            return966        handle_event(967            self.handlers,968            "on_chain_error",969            "ignore_chain",970            error,971            run_id=self.run_id,972            parent_run_id=self.parent_run_id,973            tags=self.tags,974            **kwargs,975        )976977    def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:978        """Run when agent action is received.979980        Args:981            action: The agent action.982            **kwargs: Additional keyword arguments.983        """984        if not self.handlers:985            return986        handle_event(987            self.handlers,988            "on_agent_action",989            "ignore_agent",990            action,991            run_id=self.run_id,992            parent_run_id=self.parent_run_id,993            tags=self.tags,994            **kwargs,995        )996997    def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:998        """Run when agent finish is received.9991000        Args:1001            finish: The agent finish.1002            **kwargs: Additional keyword arguments.1003        """1004        if not self.handlers:1005            return1006        handle_event(1007            self.handlers,1008            "on_agent_finish",1009            "ignore_agent",1010            finish,1011            run_id=self.run_id,1012            parent_run_id=self.parent_run_id,1013            tags=self.tags,1014            **kwargs,1015        )101610171018class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):1019    """Async callback manager for chain run."""10201021    def get_sync(self) -> CallbackManagerForChainRun:1022        """Get the equivalent sync `RunManager`.10231024        Returns:1025            The sync `RunManager`.1026        """1027        return CallbackManagerForChainRun(1028            run_id=self.run_id,1029            handlers=self.handlers,1030            inheritable_handlers=self.inheritable_handlers,1031            parent_run_id=self.parent_run_id,1032            tags=self.tags,1033            inheritable_tags=self.inheritable_tags,1034            metadata=self.metadata,1035            inheritable_metadata=self.inheritable_metadata,1036        )10371038    @shielded1039    async def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1040        """Run when a chain ends running.10411042        Args:1043            outputs: The outputs of the chain.1044            **kwargs: Additional keyword arguments.10451046        """1047        if not self.handlers:1048            return1049        await ahandle_event(1050            self.handlers,1051            "on_chain_end",1052            "ignore_chain",1053            outputs,1054            run_id=self.run_id,1055            parent_run_id=self.parent_run_id,1056            tags=self.tags,1057            **kwargs,1058        )10591060    @shielded1061    async def on_chain_error(1062        self,1063        error: BaseException,1064        **kwargs: Any,1065    ) -> None:1066        """Run when chain errors.10671068        Args:1069            error: The error.1070            **kwargs: Additional keyword arguments.10711072        """1073        if not self.handlers:1074            return1075        await ahandle_event(1076            self.handlers,1077            "on_chain_error",1078            "ignore_chain",1079            error,1080            run_id=self.run_id,1081            parent_run_id=self.parent_run_id,1082            tags=self.tags,1083            **kwargs,1084        )10851086    async def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:1087        """Run when agent action is received.10881089        Args:1090            action: The agent action.1091            **kwargs: Additional keyword arguments.1092        """1093        if not self.handlers:1094            return1095        await ahandle_event(1096            self.handlers,1097            "on_agent_action",1098            "ignore_agent",1099            action,1100            run_id=self.run_id,1101            parent_run_id=self.parent_run_id,1102            tags=self.tags,1103            **kwargs,1104        )11051106    async def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:1107        """Run when agent finish is received.11081109        Args:1110            finish: The agent finish.1111            **kwargs: Additional keyword arguments.1112        """1113        if not self.handlers:1114            return1115        await ahandle_event(1116            self.handlers,1117            "on_agent_finish",1118            "ignore_agent",1119            finish,1120            run_id=self.run_id,1121            parent_run_id=self.parent_run_id,1122            tags=self.tags,1123            **kwargs,1124        )112511261127class CallbackManagerForToolRun(ParentRunManager, ToolManagerMixin):1128    """Callback manager for tool run."""11291130    def on_tool_end(1131        self,1132        output: Any,1133        **kwargs: Any,1134    ) -> None:1135        """Run when the tool ends running.11361137        Args:1138            output: The output of the tool.1139            **kwargs: The keyword arguments to pass to the event handler11401141        """1142        if not self.handlers:1143            return1144        handle_event(1145            self.handlers,1146            "on_tool_end",1147            "ignore_agent",1148            output,1149            run_id=self.run_id,1150            parent_run_id=self.parent_run_id,1151            tags=self.tags,1152            **kwargs,1153        )11541155    def on_tool_error(1156        self,1157        error: BaseException,1158        **kwargs: Any,1159    ) -> None:1160        """Run when tool errors.11611162        Args:1163            error: The error.1164            **kwargs: Additional keyword arguments.11651166        """1167        if not self.handlers:1168            return1169        handle_event(1170            self.handlers,1171            "on_tool_error",1172            "ignore_agent",1173            error,1174            run_id=self.run_id,1175            parent_run_id=self.parent_run_id,1176            tags=self.tags,1177            **kwargs,1178        )117911801181class AsyncCallbackManagerForToolRun(AsyncParentRunManager, ToolManagerMixin):1182    """Async callback manager for tool run."""11831184    def get_sync(self) -> CallbackManagerForToolRun:1185        """Get the equivalent sync `RunManager`.11861187        Returns:1188            The sync `RunManager`.1189        """1190        return CallbackManagerForToolRun(1191            run_id=self.run_id,1192            handlers=self.handlers,1193            inheritable_handlers=self.inheritable_handlers,1194            parent_run_id=self.parent_run_id,1195            tags=self.tags,1196            inheritable_tags=self.inheritable_tags,1197            metadata=self.metadata,1198            inheritable_metadata=self.inheritable_metadata,1199        )12001201    async def on_tool_end(self, output: Any, **kwargs: Any) -> None:1202        """Async run when the tool ends running.12031204        Args:1205            output: The output of the tool.1206            **kwargs: Additional keyword arguments.12071208        """1209        if not self.handlers:1210            return1211        await ahandle_event(1212            self.handlers,1213            "on_tool_end",1214            "ignore_agent",1215            output,1216            run_id=self.run_id,1217            parent_run_id=self.parent_run_id,1218            tags=self.tags,1219            **kwargs,1220        )12211222    async def on_tool_error(1223        self,1224        error: BaseException,1225        **kwargs: Any,1226    ) -> None:1227        """Run when tool errors.12281229        Args:1230            error: The error.1231            **kwargs: Additional keyword arguments.12321233        """1234        if not self.handlers:1235            return1236        await ahandle_event(1237            self.handlers,1238            "on_tool_error",1239            "ignore_agent",1240            error,1241            run_id=self.run_id,1242            parent_run_id=self.parent_run_id,1243            tags=self.tags,1244            **kwargs,1245        )124612471248class CallbackManagerForRetrieverRun(ParentRunManager, RetrieverManagerMixin):1249    """Callback manager for retriever run."""12501251    def on_retriever_end(1252        self,1253        documents: Sequence[Document],1254        **kwargs: Any,1255    ) -> None:1256        """Run when retriever ends running.12571258        Args:1259            documents: The retrieved documents.1260            **kwargs: Additional keyword arguments.12611262        """1263        if not self.handlers:1264            return1265        handle_event(1266            self.handlers,1267            "on_retriever_end",1268            "ignore_retriever",1269            documents,1270            run_id=self.run_id,1271            parent_run_id=self.parent_run_id,1272            tags=self.tags,1273            **kwargs,1274        )12751276    def on_retriever_error(1277        self,1278        error: BaseException,1279        **kwargs: Any,1280    ) -> None:1281        """Run when retriever errors.12821283        Args:1284            error: The error.1285            **kwargs: Additional keyword arguments.12861287        """1288        if not self.handlers:1289            return1290        handle_event(1291            self.handlers,1292            "on_retriever_error",1293            "ignore_retriever",1294            error,1295            run_id=self.run_id,1296            parent_run_id=self.parent_run_id,1297            tags=self.tags,1298            **kwargs,1299        )130013011302class AsyncCallbackManagerForRetrieverRun(1303    AsyncParentRunManager,1304    RetrieverManagerMixin,1305):1306    """Async callback manager for retriever run."""13071308    def get_sync(self) -> CallbackManagerForRetrieverRun:1309        """Get the equivalent sync `RunManager`.13101311        Returns:1312            The sync `RunManager`.13131314        """1315        return CallbackManagerForRetrieverRun(1316            run_id=self.run_id,1317            handlers=self.handlers,1318            inheritable_handlers=self.inheritable_handlers,1319            parent_run_id=self.parent_run_id,1320            tags=self.tags,1321            inheritable_tags=self.inheritable_tags,1322            metadata=self.metadata,1323            inheritable_metadata=self.inheritable_metadata,1324        )13251326    @shielded1327    async def on_retriever_end(1328        self, documents: Sequence[Document], **kwargs: Any1329    ) -> None:1330        """Run when the retriever ends running.13311332        Args:1333            documents: The retrieved documents.1334            **kwargs: Additional keyword arguments.13351336        """1337        if not self.handlers:1338            return1339        await ahandle_event(1340            self.handlers,1341            "on_retriever_end",1342            "ignore_retriever",1343            documents,1344            run_id=self.run_id,1345            parent_run_id=self.parent_run_id,1346            tags=self.tags,1347            **kwargs,1348        )13491350    @shielded1351    async def on_retriever_error(1352        self,1353        error: BaseException,1354        **kwargs: Any,1355    ) -> None:1356        """Run when retriever errors.13571358        Args:1359            error: The error.1360            **kwargs: Additional keyword arguments.13611362        """1363        if not self.handlers:1364            return1365        await ahandle_event(1366            self.handlers,1367            "on_retriever_error",1368            "ignore_retriever",1369            error,1370            run_id=self.run_id,1371            parent_run_id=self.parent_run_id,1372            tags=self.tags,1373            **kwargs,1374        )137513761377class CallbackManager(BaseCallbackManager):1378    """Callback manager for LangChain."""13791380    def on_llm_start(1381        self,1382        serialized: dict[str, Any],1383        prompts: list[str],1384        run_id: UUID | None = None,1385        **kwargs: Any,1386    ) -> list[CallbackManagerForLLMRun]:1387        """Run when LLM starts running.13881389        Args:1390            serialized: The serialized LLM.1391            prompts: The list of prompts.1392            run_id: The ID of the run.1393            **kwargs: Additional keyword arguments.13941395        Returns:1396            A callback manager for each prompt as an LLM run.13971398        """1399        managers = []1400        for i, prompt in enumerate(prompts):1401            # Can't have duplicate runs with the same run ID (if provided)1402            run_id_ = run_id if i == 0 and run_id is not None else uuid7()1403            handle_event(1404                self.handlers,1405                "on_llm_start",1406                "ignore_llm",1407                serialized,1408                [prompt],1409                run_id=run_id_,1410                parent_run_id=self.parent_run_id,1411                tags=self.tags,1412                metadata=self.metadata,1413                **kwargs,1414            )14151416            managers.append(1417                CallbackManagerForLLMRun(1418                    run_id=run_id_,1419                    handlers=self.handlers,1420                    inheritable_handlers=self.inheritable_handlers,1421                    parent_run_id=self.parent_run_id,1422                    tags=self.tags,1423                    inheritable_tags=self.inheritable_tags,1424                    metadata=self.metadata,1425                    inheritable_metadata=self.inheritable_metadata,1426                )1427            )14281429        return managers14301431    def on_chat_model_start(1432        self,1433        serialized: dict[str, Any],1434        messages: list[list[BaseMessage]],1435        run_id: UUID | None = None,1436        **kwargs: Any,1437    ) -> list[CallbackManagerForLLMRun]:1438        """Run when chat model starts running.14391440        Args:1441            serialized: The serialized LLM.1442            messages: The list of messages.1443            run_id: The ID of the run.1444            **kwargs: Additional keyword arguments.14451446        Returns:1447            A callback manager for each list of messages as an LLM run.14481449        """1450        managers = []1451        for message_list in messages:1452            if run_id is not None:1453                run_id_ = run_id1454                run_id = None1455            else:1456                run_id_ = uuid7()1457            handle_event(1458                self.handlers,1459                "on_chat_model_start",1460                "ignore_chat_model",1461                serialized,1462                [message_list],1463                run_id=run_id_,1464                parent_run_id=self.parent_run_id,1465                tags=self.tags,1466                metadata=self.metadata,1467                **kwargs,1468            )14691470            managers.append(1471                CallbackManagerForLLMRun(1472                    run_id=run_id_,1473                    handlers=self.handlers,1474                    inheritable_handlers=self.inheritable_handlers,1475                    parent_run_id=self.parent_run_id,1476                    tags=self.tags,1477                    inheritable_tags=self.inheritable_tags,1478                    metadata=self.metadata,1479                    inheritable_metadata=self.inheritable_metadata,1480                )1481            )14821483        return managers14841485    def on_chain_start(1486        self,1487        serialized: dict[str, Any] | None,1488        inputs: dict[str, Any] | Any,1489        run_id: UUID | None = None,1490        **kwargs: Any,1491    ) -> CallbackManagerForChainRun:1492        """Run when chain starts running.14931494        Args:1495            serialized: The serialized chain.1496            inputs: The inputs to the chain.1497            run_id: The ID of the run.1498            **kwargs: Additional keyword arguments.14991500        Returns:1501            The callback manager for the chain run.15021503        """1504        if run_id is None:1505            run_id = uuid7()1506        handle_event(1507            self.handlers,1508            "on_chain_start",1509            "ignore_chain",1510            serialized,1511            inputs,1512            run_id=run_id,1513            parent_run_id=self.parent_run_id,1514            tags=self.tags,1515            metadata=self.metadata,1516            **kwargs,1517        )15181519        return CallbackManagerForChainRun(1520            run_id=run_id,1521            handlers=self.handlers,1522            inheritable_handlers=self.inheritable_handlers,1523            parent_run_id=self.parent_run_id,1524            tags=self.tags,1525            inheritable_tags=self.inheritable_tags,1526            metadata=self.metadata,1527            inheritable_metadata=self.inheritable_metadata,1528        )15291530    @override1531    def on_tool_start(1532        self,1533        serialized: dict[str, Any] | None,1534        input_str: str,1535        run_id: UUID | None = None,1536        parent_run_id: UUID | None = None,1537        inputs: dict[str, Any] | None = None,1538        **kwargs: Any,1539    ) -> CallbackManagerForToolRun:1540        """Run when tool starts running.15411542        Args:1543            serialized: Serialized representation of the tool.1544            input_str: The  input to the tool as a string.15451546                Non-string inputs are cast to strings.1547            run_id: ID for the run.1548            parent_run_id: The ID of the parent run.1549            inputs: The original input to the tool if provided.15501551                Recommended for usage instead of input_str when the original input is1552                needed.15531554                If provided, the inputs are expected to be formatted as a dict. The keys1555                will correspond to the named-arguments in the tool.1556            **kwargs: The keyword arguments to pass to the event handler15571558        Returns:1559            The callback manager for the tool run.15601561        """1562        if run_id is None:1563            run_id = uuid7()15641565        handle_event(1566            self.handlers,1567            "on_tool_start",1568            "ignore_agent",1569            serialized,1570            input_str,1571            run_id=run_id,1572            parent_run_id=self.parent_run_id,1573            tags=self.tags,1574            metadata=self.metadata,1575            inputs=inputs,1576            **kwargs,1577        )15781579        return CallbackManagerForToolRun(1580            run_id=run_id,1581            handlers=self.handlers,1582            inheritable_handlers=self.inheritable_handlers,1583            parent_run_id=self.parent_run_id,1584            tags=self.tags,1585            inheritable_tags=self.inheritable_tags,1586            metadata=self.metadata,1587            inheritable_metadata=self.inheritable_metadata,1588        )15891590    @override1591    def on_retriever_start(1592        self,1593        serialized: dict[str, Any] | None,1594        query: str,1595        run_id: UUID | None = None,1596        parent_run_id: UUID | None = None,1597        **kwargs: Any,1598    ) -> CallbackManagerForRetrieverRun:1599        """Run when the retriever starts running.16001601        Args:1602            serialized: The serialized retriever.1603            query: The query.1604            run_id: The ID of the run.1605            parent_run_id: The ID of the parent run.1606            **kwargs: Additional keyword arguments.16071608        Returns:1609            The callback manager for the retriever run.1610        """1611        if run_id is None:1612            run_id = uuid7()16131614        handle_event(1615            self.handlers,1616            "on_retriever_start",1617            "ignore_retriever",1618            serialized,1619            query,1620            run_id=run_id,1621            parent_run_id=self.parent_run_id,1622            tags=self.tags,1623            metadata=self.metadata,1624            **kwargs,1625        )16261627        return CallbackManagerForRetrieverRun(1628            run_id=run_id,1629            handlers=self.handlers,1630            inheritable_handlers=self.inheritable_handlers,1631            parent_run_id=self.parent_run_id,1632            tags=self.tags,1633            inheritable_tags=self.inheritable_tags,1634            metadata=self.metadata,1635            inheritable_metadata=self.inheritable_metadata,1636        )16371638    def on_custom_event(1639        self,1640        name: str,1641        data: Any,1642        run_id: UUID | None = None,1643        **kwargs: Any,1644    ) -> None:1645        """Dispatch an adhoc event to the handlers (async version).16461647        This event should NOT be used in any internal LangChain code. The event is meant1648        specifically for users of the library to dispatch custom events that are1649        tailored to their application.16501651        Args:1652            name: The name of the adhoc event.1653            data: The data for the adhoc event.1654            run_id: The ID of the run.16551656        Raises:1657            ValueError: If additional keyword arguments are passed.1658        """1659        if not self.handlers:1660            return1661        if kwargs:1662            msg = (1663                "The dispatcher API does not accept additional keyword arguments."1664                "Please do not pass any additional keyword arguments, instead "1665                "include them in the data field."1666            )1667            raise ValueError(msg)1668        if run_id is None:1669            run_id = uuid7()16701671        handle_event(1672            self.handlers,1673            "on_custom_event",1674            "ignore_custom_event",1675            name,1676            data,1677            run_id=run_id,1678            tags=self.tags,1679            metadata=self.metadata,1680        )16811682    @classmethod1683    def configure(1684        cls,1685        inheritable_callbacks: Callbacks = None,1686        local_callbacks: Callbacks = None,1687        verbose: bool = False,  # noqa: FBT001,FBT0021688        inheritable_tags: list[str] | None = None,1689        local_tags: list[str] | None = None,1690        inheritable_metadata: dict[str, Any] | None = None,1691        local_metadata: dict[str, Any] | None = None,1692        *,1693        langsmith_inheritable_metadata: Mapping[str, Any] | None = None,1694        langsmith_inheritable_tags: list[str] | None = None,1695    ) -> CallbackManager:1696        """Configure the callback manager.16971698        Args:1699            inheritable_callbacks: The inheritable callbacks.1700            local_callbacks: The local callbacks.1701            verbose: Whether to enable verbose mode.1702            inheritable_tags: The inheritable tags.1703            local_tags: The local tags.1704            inheritable_metadata: The inheritable metadata.1705            local_metadata: The local metadata.1706            langsmith_inheritable_metadata: Default inheritable metadata applied1707                to any `LangChainTracer` handlers via `set_defaults`.1708            langsmith_inheritable_tags: Default inheritable tags applied to any1709                `LangChainTracer` handlers via `set_defaults`.17101711        Returns:1712            The configured callback manager.1713        """1714        return _configure(1715            cls,1716            inheritable_callbacks,1717            local_callbacks,1718            inheritable_tags,1719            local_tags,1720            inheritable_metadata,1721            local_metadata,1722            verbose=verbose,1723            langsmith_inheritable_metadata=langsmith_inheritable_metadata,1724            langsmith_inheritable_tags=langsmith_inheritable_tags,1725        )172617271728class CallbackManagerForChainGroup(CallbackManager):1729    """Callback manager for the chain group."""17301731    def __init__(1732        self,1733        handlers: list[BaseCallbackHandler],1734        inheritable_handlers: list[BaseCallbackHandler] | None = None,1735        parent_run_id: UUID | None = None,1736        *,1737        parent_run_manager: CallbackManagerForChainRun,1738        **kwargs: Any,1739    ) -> None:1740        """Initialize the callback manager.17411742        Args:1743            handlers: The list of handlers.1744            inheritable_handlers: The list of inheritable handlers.1745            parent_run_id: The ID of the parent run.1746            parent_run_manager: The parent run manager.1747            **kwargs: Additional keyword arguments.17481749        """1750        super().__init__(1751            handlers,1752            inheritable_handlers,1753            parent_run_id,1754            **kwargs,1755        )1756        self.parent_run_manager = parent_run_manager1757        self.ended = False17581759    @override1760    def copy(self) -> CallbackManagerForChainGroup:1761        return self.__class__(1762            handlers=self.handlers.copy(),1763            inheritable_handlers=self.inheritable_handlers.copy(),1764            parent_run_id=self.parent_run_id,1765            tags=self.tags.copy(),1766            inheritable_tags=self.inheritable_tags.copy(),1767            metadata=self.metadata.copy(),1768            inheritable_metadata=self.inheritable_metadata.copy(),1769            parent_run_manager=self.parent_run_manager,1770        )17711772    def merge(1773        self: CallbackManagerForChainGroup, other: BaseCallbackManager1774    ) -> CallbackManagerForChainGroup:1775        """Merge the group callback manager with another callback manager.17761777        Overwrites the merge method in the base class to ensure that the parent run1778        manager is preserved. Keeps the `parent_run_manager` from the current object.17791780        Returns:1781            A copy of the current object with the handlers, tags, and other attributes1782            merged from the other object.17831784        Example:1785            ```python1786            # Merging two callback managers1787            from langchain_core.callbacks.manager import (1788                CallbackManager,1789                trace_as_chain_group,1790            )1791            from langchain_core.callbacks.stdout import StdOutCallbackHandler17921793            manager = CallbackManager(handlers=[StdOutCallbackHandler()], tags=["tag2"])1794            with trace_as_chain_group("My Group Name", tags=["tag1"]) as group_manager:1795                merged_manager = group_manager.merge(manager)1796                print(type(merged_manager))1797                # <class 'langchain_core.callbacks.manager.CallbackManagerForChainGroup'>17981799                print(merged_manager.handlers)1800                # [1801                #    <langchain_core.callbacks.stdout.LangChainTracer object at ...>,1802                #    <langchain_core.callbacks.streaming_stdout.StdOutCallbackHandler object at ...>,1803                # ]18041805                print(merged_manager.tags)1806                #    ['tag2', 'tag1']1807            ```1808        """  # noqa: E5011809        manager = self.__class__(1810            parent_run_id=self.parent_run_id or other.parent_run_id,1811            handlers=[],1812            inheritable_handlers=[],1813            tags=list(set(self.tags + other.tags)),1814            inheritable_tags=list(set(self.inheritable_tags + other.inheritable_tags)),1815            metadata={1816                **self.metadata,1817                **other.metadata,1818            },1819            parent_run_manager=self.parent_run_manager,1820        )18211822        handlers = self.handlers + other.handlers1823        inheritable_handlers = self.inheritable_handlers + other.inheritable_handlers18241825        for handler in handlers:1826            manager.add_handler(handler)18271828        for handler in inheritable_handlers:1829            manager.add_handler(handler, inherit=True)1830        return manager18311832    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1833        """Run when traced chain group ends.18341835        Args:1836            outputs: The outputs of the chain.1837            **kwargs: Additional keyword arguments.18381839        """1840        self.ended = True1841        return self.parent_run_manager.on_chain_end(outputs, **kwargs)18421843    def on_chain_error(1844        self,1845        error: BaseException,1846        **kwargs: Any,1847    ) -> None:1848        """Run when chain errors.18491850        Args:1851            error: The error.1852            **kwargs: Additional keyword arguments.18531854        """1855        self.ended = True1856        return self.parent_run_manager.on_chain_error(error, **kwargs)185718581859class AsyncCallbackManager(BaseCallbackManager):1860    """Async callback manager that handles callbacks from LangChain."""18611862    @property1863    def is_async(self) -> bool:1864        """Return whether the handler is async."""1865        return True18661867    async def on_llm_start(1868        self,1869        serialized: dict[str, Any],1870        prompts: list[str],1871        run_id: UUID | None = None,1872        **kwargs: Any,1873    ) -> list[AsyncCallbackManagerForLLMRun]:1874        """Run when LLM starts running.18751876        Args:1877            serialized: The serialized LLM.1878            prompts: The list of prompts.1879            run_id: The ID of the run.1880            **kwargs: Additional keyword arguments.18811882        Returns:1883            The list of async callback managers, one for each LLM run corresponding to1884            each prompt.1885        """1886        inline_tasks = []1887        non_inline_tasks = []1888        inline_handlers = [handler for handler in self.handlers if handler.run_inline]1889        non_inline_handlers = [1890            handler for handler in self.handlers if not handler.run_inline1891        ]1892        managers = []18931894        for prompt in prompts:1895            if run_id is not None:1896                run_id_ = run_id1897                run_id = None1898            else:1899                run_id_ = uuid7()19001901            if inline_handlers:1902                inline_tasks.append(1903                    ahandle_event(1904                        inline_handlers,1905                        "on_llm_start",1906                        "ignore_llm",1907                        serialized,1908                        [prompt],1909                        run_id=run_id_,1910                        parent_run_id=self.parent_run_id,1911                        tags=self.tags,1912                        metadata=self.metadata,1913                        **kwargs,1914                    )1915                )1916            else:1917                non_inline_tasks.append(1918                    ahandle_event(1919                        non_inline_handlers,1920                        "on_llm_start",1921                        "ignore_llm",1922                        serialized,1923                        [prompt],1924                        run_id=run_id_,1925                        parent_run_id=self.parent_run_id,1926                        tags=self.tags,1927                        metadata=self.metadata,1928                        **kwargs,1929                    )1930                )19311932            managers.append(1933                AsyncCallbackManagerForLLMRun(1934                    run_id=run_id_,1935                    handlers=self.handlers,1936                    inheritable_handlers=self.inheritable_handlers,1937                    parent_run_id=self.parent_run_id,1938                    tags=self.tags,1939                    inheritable_tags=self.inheritable_tags,1940                    metadata=self.metadata,1941                    inheritable_metadata=self.inheritable_metadata,1942                )1943            )19441945        # Run inline tasks sequentially1946        for inline_task in inline_tasks:1947            await inline_task19481949        # Run non-inline tasks concurrently1950        if non_inline_tasks:1951            await asyncio.gather(*non_inline_tasks)19521953        return managers19541955    async def on_chat_model_start(1956        self,1957        serialized: dict[str, Any],1958        messages: list[list[BaseMessage]],1959        run_id: UUID | None = None,1960        **kwargs: Any,1961    ) -> list[AsyncCallbackManagerForLLMRun]:1962        """Async run when LLM starts running.19631964        Args:1965            serialized: The serialized LLM.1966            messages: The list of messages.1967            run_id: The ID of the run.1968            **kwargs: Additional keyword arguments.19691970        Returns:1971            The list of async callback managers, one for each LLM run corresponding to1972            each inner message list.1973        """1974        inline_tasks = []1975        non_inline_tasks = []1976        managers = []19771978        for message_list in messages:1979            if run_id is not None:1980                run_id_ = run_id1981                run_id = None1982            else:1983                run_id_ = uuid7()19841985            for handler in self.handlers:1986                task = ahandle_event(1987                    [handler],1988                    "on_chat_model_start",1989                    "ignore_chat_model",1990                    serialized,1991                    [message_list],1992                    run_id=run_id_,1993                    parent_run_id=self.parent_run_id,1994                    tags=self.tags,1995                    metadata=self.metadata,1996                    **kwargs,1997                )1998                if handler.run_inline:1999                    inline_tasks.append(task)2000                else:

Code quality findings 74

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 try blocks have corresponding except or finally blocks
try-without-except
try:
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.