libs/core/langchain_core/callbacks/manager.py PYTHON 2,828 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,828.
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 langsmith.address import AgentAddress41    from tenacity import RetryCallState4243    from langchain_core.agents import AgentAction, AgentFinish44    from langchain_core.documents import Document45    from langchain_core.outputs import ChatGenerationChunk, GenerationChunk, LLMResult46    from langchain_core.runnables.config import RunnableConfig47    from langchain_core.tracers.schemas import Run4849logger = logging.getLogger(__name__)505152def _get_debug() -> bool:53    return get_debug()545556@contextmanager57def trace_as_chain_group(58    group_name: str,59    callback_manager: CallbackManager | None = None,60    *,61    inputs: dict[str, Any] | None = None,62    project_name: str | None = None,63    address: AgentAddress | None = None,64    example_id: str | UUID | None = None,65    run_id: UUID | None = None,66    tags: list[str] | None = None,67    metadata: dict[str, Any] | None = None,68) -> Generator[CallbackManagerForChainGroup, None, None]:69    """Get a callback manager for a chain group in a context manager.7071    Useful for grouping different calls together as a single run even if they aren't72    composed in a single chain.7374    Args:75        group_name: The name of the chain group.76        callback_manager: The callback manager to use.77        inputs: The inputs to the chain group.78        project_name: The name of the project.79        address: The agent address to send traces to instead of a project.8081            !!! warning "Beta"82                Agent addressing must be enabled for the LangSmith workspace.83        example_id: The ID of the example.84        run_id: The ID of the run.85        tags: The inheritable tags to apply to all runs.86        metadata: The metadata to apply to all runs.8788    !!! note8990        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in91        LangSmith.9293    Yields:94        The callback manager for the chain group.9596    Example:97        ```python98        llm_input = "Foo"99        with trace_as_chain_group("group_name", inputs={"input": llm_input}) as manager:100            # Use the callback manager for the chain group101            res = llm.invoke(llm_input, {"callbacks": manager})102            manager.on_chain_end({"output": res})103        ```104    """105    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level106        _get_trace_callbacks,107    )108109    cb = _get_trace_callbacks(110        project_name, example_id, callback_manager=callback_manager, address=address111    )112    cm = CallbackManager.configure(113        inheritable_callbacks=cb,114        inheritable_tags=tags,115        inheritable_metadata=metadata,116    )117118    run_manager = cm.on_chain_start({"name": group_name}, inputs or {}, run_id=run_id)119    child_cm = run_manager.get_child()120    group_cm = CallbackManagerForChainGroup(121        child_cm.handlers,122        child_cm.inheritable_handlers,123        child_cm.parent_run_id,124        parent_run_manager=run_manager,125        tags=child_cm.tags,126        inheritable_tags=child_cm.inheritable_tags,127        metadata=child_cm.metadata,128        inheritable_metadata=child_cm.inheritable_metadata,129    )130    try:131        yield group_cm132    except BaseException as e:133        if not group_cm.ended:134            run_manager.on_chain_error(e)135        raise136    else:137        if not group_cm.ended:138            run_manager.on_chain_end({})139140141@asynccontextmanager142async def atrace_as_chain_group(143    group_name: str,144    callback_manager: AsyncCallbackManager | None = None,145    *,146    inputs: dict[str, Any] | None = None,147    project_name: str | None = None,148    address: AgentAddress | None = None,149    example_id: str | UUID | None = None,150    run_id: UUID | None = None,151    tags: list[str] | None = None,152    metadata: dict[str, Any] | None = None,153) -> AsyncGenerator[AsyncCallbackManagerForChainGroup, None]:154    """Get an async callback manager for a chain group in a context manager.155156    Useful for grouping different async calls together as a single run even if they157    aren't composed in a single chain.158159    Args:160        group_name: The name of the chain group.161        callback_manager: The async callback manager to use, which manages tracing and162            other callback behavior.163        inputs: The inputs to the chain group.164        project_name: The name of the project.165        address: The agent address to send traces to instead of a project.166167            !!! warning "Beta"168                Agent addressing must be enabled for the LangSmith workspace.169        example_id: The ID of the example.170        run_id: The ID of the run.171        tags: The inheritable tags to apply to all runs.172        metadata: The metadata to apply to all runs.173174    Yields:175        The async callback manager for the chain group.176177    !!! note178179        Must have `LANGCHAIN_TRACING_V2` env var set to true to see the trace in180        LangSmith.181182    Example:183        ```python184        llm_input = "Foo"185        async with atrace_as_chain_group(186            "group_name", inputs={"input": llm_input}187        ) as manager:188            # Use the async callback manager for the chain group189            res = await llm.ainvoke(llm_input, {"callbacks": manager})190            await manager.on_chain_end({"output": res})191        ```192    """193    from langchain_core.tracers.context import (  # noqa: PLC0415 -- deferred to avoid importing langsmith at module level194        _get_trace_callbacks,195    )196197    cb = _get_trace_callbacks(198        project_name, example_id, callback_manager=callback_manager, address=address199    )200    cm = AsyncCallbackManager.configure(201        inheritable_callbacks=cb, inheritable_tags=tags, inheritable_metadata=metadata202    )203204    run_manager = await cm.on_chain_start(205        {"name": group_name}, inputs or {}, run_id=run_id206    )207    child_cm = run_manager.get_child()208    group_cm = AsyncCallbackManagerForChainGroup(209        child_cm.handlers,210        child_cm.inheritable_handlers,211        child_cm.parent_run_id,212        parent_run_manager=run_manager,213        tags=child_cm.tags,214        inheritable_tags=child_cm.inheritable_tags,215        metadata=child_cm.metadata,216        inheritable_metadata=child_cm.inheritable_metadata,217    )218    try:219        yield group_cm220    except BaseException as e:221        if not group_cm.ended:222            await run_manager.on_chain_error(e)223        raise224    else:225        if not group_cm.ended:226            await run_manager.on_chain_end({})227228229Func = TypeVar("Func", bound=Callable[..., Any])230231232def shielded(func: Func) -> Func:233    """Makes so an awaitable method is always shielded from cancellation.234235    Args:236        func: The function to shield.237238    Returns:239        The shielded function240241    """242243    @functools.wraps(func)244    async def wrapped(*args: Any, **kwargs: Any) -> Any:245        # Capture the current context to preserve context variables246        ctx = copy_context()247248        # Create the coroutine249        coro = func(*args, **kwargs)250251        # For Python 3.11+, create task with explicit context252        # For older versions, fallback to original behavior253        try:254            # Create a task with the captured context to preserve context variables255            task = asyncio.create_task(coro, context=ctx)  # type: ignore[call-arg, unused-ignore]256            # `call-arg` used to not fail 3.9 or 3.10 tests257            return await asyncio.shield(task)258        except TypeError:259            # Python < 3.11 fallback - create task normally then shield260            # This won't preserve context perfectly but is better than nothing261            task = asyncio.create_task(coro)262            return await asyncio.shield(task)263264    return cast("Func", wrapped)265266267async def _achat_model_start_fallback(268    coro: Coroutine[Any, Any, Any],269    handler: BaseCallbackHandler,270    *args: Any,271    **kwargs: Any,272) -> None:273    """Wrap an async `on_chat_model_start` coroutine with fallback.274275    Catches `NotImplementedError` and triggers the `on_llm_start` fallback.276    This covers async handlers invoked from a **sync** `handle_event` call,277    where the coroutine is collected into `coros` and executed later by278    `_run_coros`. Without this wrapper the `NotImplementedError` would be279    caught generically by `_run_coros` and the trace would be lost.280    """281    try:282        await coro283    except NotImplementedError:284        message_strings = [get_buffer_string(m) for m in args[1]]285        await _ahandle_event_for_handler(286            handler,287            "on_llm_start",288            "ignore_llm",289            args[0],290            message_strings,291            *args[2:],292            **kwargs,293        )294295296def handle_event(297    handlers: list[BaseCallbackHandler],298    event_name: str,299    ignore_condition_name: str | None,300    *args: Any,301    **kwargs: Any,302) -> None:303    """Generic event handler for `CallbackManager`.304305    Args:306        handlers: The list of handlers that will handle the event.307        event_name: The name of the event (e.g., `'on_llm_start'`).308        ignore_condition_name: Name of the attribute defined on handler that if `True`309            will cause the handler to be skipped for the given event.310        *args: The arguments to pass to the event handler.311        **kwargs: The keyword arguments to pass to the event handler312313    """314    coros: list[Coroutine[Any, Any, Any]] = []315316    try:317        message_strings: list[str] | None = None318        for handler in handlers:319            try:320                if ignore_condition_name is None or not getattr(321                    handler, ignore_condition_name322                ):323                    event = getattr(handler, event_name)(*args, **kwargs)324                    if asyncio.iscoroutine(event):325                        if event_name == "on_chat_model_start":326                            event = _achat_model_start_fallback(327                                event, handler, *args, **kwargs328                            )329                        coros.append(event)330            except NotImplementedError as e:331                if event_name == "on_chat_model_start":332                    if message_strings is None:333                        message_strings = [get_buffer_string(m) for m in args[1]]334                    handle_event(335                        [handler],336                        "on_llm_start",337                        "ignore_llm",338                        args[0],339                        message_strings,340                        *args[2:],341                        **kwargs,342                    )343                else:344                    handler_name = handler.__class__.__name__345                    logger.warning(346                        "NotImplementedError in %s.%s callback: %s",347                        handler_name,348                        event_name,349                        repr(e),350                    )351            except Exception as e:352                logger.warning(353                    "Error in %s.%s callback: %s",354                    handler.__class__.__name__,355                    event_name,356                    repr(e),357                )358                if handler.raise_error:359                    raise360    finally:361        if coros:362            try:363                # Raises RuntimeError if there is no current event loop.364                asyncio.get_running_loop()365                loop_running = True366            except RuntimeError:367                loop_running = False368369            if loop_running:370                # If we try to submit this coroutine to the running loop371                # we end up in a deadlock, as we'd have gotten here from a372                # running coroutine, which we cannot interrupt to run this one.373                # The solution is to run the synchronous function on the globally shared374                # thread pool executor to avoid blocking the main event loop.375                _executor().submit(copy_context().run, _run_coros, coros).result()376            else:377                # If there's no running loop, we can run the coroutines directly.378                _run_coros(coros)379380381def _run_coros(coros: list[Coroutine[Any, Any, Any]]) -> None:382    # Note: exceptions raised by these coroutines are always logged and swallowed383    # here, regardless of the handler's `raise_error` setting. Async-handler errors384    # driven through sync `handle_event` therefore never propagate, unlike errors385    # from sync handlers (which honor `raise_error`). This is a pre-existing386    # asymmetry between the sync and async callback paths.387    if hasattr(asyncio, "Runner"):388        # Python 3.11+389        # Run the coroutines in a new event loop, taking care to390        # - install signal handlers391        # - run pending tasks scheduled by `coros`392        # - close asyncgens and executors393        # - close the loop394        with asyncio.Runner() as runner:395            # Run the coroutine, get the result396            for coro in coros:397                try:398                    runner.run(coro)399                except Exception as e:400                    logger.warning("Error in callback coroutine: %s", repr(e))401402            # Run pending tasks scheduled by coros until they are all done403            while pending := asyncio.all_tasks(runner.get_loop()):404                runner.run(asyncio.wait(pending))405    else:406        # Before Python 3.11 we need to run each coroutine in a new event loop407        # as the Runner api is not available.408        for coro in coros:409            try:410                asyncio.run(coro)411            except Exception as e:412                logger.warning("Error in callback coroutine: %s", repr(e))413414415async def _ahandle_event_for_handler(416    handler: BaseCallbackHandler,417    event_name: str,418    ignore_condition_name: str | None,419    *args: Any,420    **kwargs: Any,421) -> None:422    try:423        if ignore_condition_name is None or not getattr(handler, ignore_condition_name):424            event = getattr(handler, event_name)425            if inspect.iscoroutinefunction(event):426                await event(*args, **kwargs)427            elif handler.run_inline:428                event(*args, **kwargs)429            else:430                await asyncio.get_running_loop().run_in_executor(431                    None,432                    functools.partial(copy_context().run, event, *args, **kwargs),433                )434    except NotImplementedError as e:435        if event_name == "on_chat_model_start":436            message_strings = [get_buffer_string(m) for m in args[1]]437            await _ahandle_event_for_handler(438                handler,439                "on_llm_start",440                "ignore_llm",441                args[0],442                message_strings,443                *args[2:],444                **kwargs,445            )446        else:447            logger.warning(448                "NotImplementedError in %s.%s callback: %s",449                handler.__class__.__name__,450                event_name,451                repr(e),452            )453    except Exception as e:454        logger.warning(455            "Error in %s.%s callback: %s",456            handler.__class__.__name__,457            event_name,458            repr(e),459        )460        if handler.raise_error:461            raise462463464async def ahandle_event(465    handlers: list[BaseCallbackHandler],466    event_name: str,467    ignore_condition_name: str | None,468    *args: Any,469    **kwargs: Any,470) -> None:471    """Async generic event handler for `AsyncCallbackManager`.472473    Args:474        handlers: The list of handlers that will handle the event.475        event_name: The name of the event (e.g., `'on_llm_start'`).476        ignore_condition_name: Name of the attribute defined on handler that if `True`477            will cause the handler to be skipped for the given event.478        *args: The arguments to pass to the event handler.479        **kwargs: The keyword arguments to pass to the event handler.480481    """482    for handler in [h for h in handlers if h.run_inline]:483        await _ahandle_event_for_handler(484            handler, event_name, ignore_condition_name, *args, **kwargs485        )486    await asyncio.gather(487        *(488            _ahandle_event_for_handler(489                handler,490                event_name,491                ignore_condition_name,492                *args,493                **kwargs,494            )495            for handler in handlers496            if not handler.run_inline497        )498    )499500501class BaseRunManager(RunManagerMixin):502    """Base class for run manager (a bound callback manager)."""503504    def __init__(505        self,506        *,507        run_id: UUID,508        handlers: list[BaseCallbackHandler],509        inheritable_handlers: list[BaseCallbackHandler],510        parent_run_id: UUID | None = None,511        tags: list[str] | None = None,512        inheritable_tags: list[str] | None = None,513        metadata: dict[str, Any] | None = None,514        inheritable_metadata: dict[str, Any] | None = None,515    ) -> None:516        """Initialize the run manager.517518        Args:519            run_id: The ID of the run.520            handlers: The list of handlers.521            inheritable_handlers: The list of inheritable handlers.522            parent_run_id: The ID of the parent run.523            tags: The list of tags.524            inheritable_tags: The list of inheritable tags.525            metadata: The metadata.526            inheritable_metadata: The inheritable metadata.527528        """529        self.run_id = run_id530        self.handlers = handlers531        self.inheritable_handlers = inheritable_handlers532        self.parent_run_id = parent_run_id533        self.tags = tags or []534        self.inheritable_tags = inheritable_tags or []535        self.metadata = metadata or {}536        self.inheritable_metadata = inheritable_metadata or {}537538    @classmethod539    def get_noop_manager(cls) -> Self:540        """Return a manager that doesn't perform any operations.541542        Returns:543            The noop manager.544545        """546        return cls(547            run_id=uuid7(),548            handlers=[],549            inheritable_handlers=[],550            tags=[],551            inheritable_tags=[],552            metadata={},553            inheritable_metadata={},554        )555556557class RunManager(BaseRunManager):558    """Synchronous run manager."""559560    def on_text(561        self,562        text: str,563        **kwargs: Any,564    ) -> None:565        """Run when a text is received.566567        Args:568            text: The received text.569            **kwargs: Additional keyword arguments.570        """571        if not self.handlers:572            return573        handle_event(574            self.handlers,575            "on_text",576            None,577            text,578            run_id=self.run_id,579            parent_run_id=self.parent_run_id,580            tags=self.tags,581            **kwargs,582        )583584    def on_retry(585        self,586        retry_state: RetryCallState,587        **kwargs: Any,588    ) -> None:589        """Run when a retry is received.590591        Args:592            retry_state: The retry state.593            **kwargs: Additional keyword arguments.594595        """596        if not self.handlers:597            return598        handle_event(599            self.handlers,600            "on_retry",601            "ignore_retry",602            retry_state,603            run_id=self.run_id,604            parent_run_id=self.parent_run_id,605            tags=self.tags,606            **kwargs,607        )608609610class ParentRunManager(RunManager):611    """Synchronous parent run manager."""612613    def get_child(self, tag: str | None = None) -> CallbackManager:614        """Get a child callback manager.615616        Args:617            tag: The tag for the child callback manager.618619        Returns:620            The child callback manager.621622        """623        manager = CallbackManager(handlers=[], parent_run_id=self.run_id)624        manager.set_handlers(self.inheritable_handlers)625        manager.add_tags(self.inheritable_tags)626        manager.add_metadata(self.inheritable_metadata)627        if tag is not None:628            manager.add_tags([tag], inherit=False)629        return manager630631632class AsyncRunManager(BaseRunManager, ABC):633    """Async run manager."""634635    @abstractmethod636    def get_sync(self) -> RunManager:637        """Get the equivalent sync `RunManager`.638639        Returns:640            The sync `RunManager`.641642        """643644    async def on_text(645        self,646        text: str,647        **kwargs: Any,648    ) -> None:649        """Run when a text is received.650651        Args:652            text: The received text.653            **kwargs: Additional keyword arguments.654        """655        if not self.handlers:656            return657        await ahandle_event(658            self.handlers,659            "on_text",660            None,661            text,662            run_id=self.run_id,663            parent_run_id=self.parent_run_id,664            tags=self.tags,665            **kwargs,666        )667668    async def on_retry(669        self,670        retry_state: RetryCallState,671        **kwargs: Any,672    ) -> None:673        """Async run when a retry is received.674675        Args:676            retry_state: The retry state.677            **kwargs: Additional keyword arguments.678679        """680        if not self.handlers:681            return682        await ahandle_event(683            self.handlers,684            "on_retry",685            "ignore_retry",686            retry_state,687            run_id=self.run_id,688            parent_run_id=self.parent_run_id,689            tags=self.tags,690            **kwargs,691        )692693694class AsyncParentRunManager(AsyncRunManager):695    """Async parent run manager."""696697    def get_child(self, tag: str | None = None) -> AsyncCallbackManager:698        """Get a child callback manager.699700        Args:701            tag: The tag for the child callback manager.702703        Returns:704            The child callback manager.705706        """707        manager = AsyncCallbackManager(handlers=[], parent_run_id=self.run_id)708        manager.set_handlers(self.inheritable_handlers)709        manager.add_tags(self.inheritable_tags)710        manager.add_metadata(self.inheritable_metadata)711        if tag is not None:712            manager.add_tags([tag], inherit=False)713        return manager714715716class CallbackManagerForLLMRun(RunManager, LLMManagerMixin):717    """Callback manager for LLM run."""718719    def on_llm_new_token(720        self,721        token: str | list[str | dict[str, Any]],722        *,723        chunk: GenerationChunk | ChatGenerationChunk | None = None,724        **kwargs: Any,725    ) -> None:726        """Run when LLM generates a new token.727728        Args:729            token: The new token, or a list of content blocks.730            chunk: The chunk.731            **kwargs: Additional keyword arguments.732733        """734        if not self.handlers:735            return736        handle_event(737            self.handlers,738            "on_llm_new_token",739            "ignore_llm",740            token=token,741            run_id=self.run_id,742            parent_run_id=self.parent_run_id,743            tags=self.tags,744            chunk=chunk,745            **kwargs,746        )747748    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:749        """Run when LLM ends running.750751        Args:752            response: The LLM result.753            **kwargs: Additional keyword arguments.754755        """756        if not self.handlers:757            return758        handle_event(759            self.handlers,760            "on_llm_end",761            "ignore_llm",762            response,763            run_id=self.run_id,764            parent_run_id=self.parent_run_id,765            tags=self.tags,766            **kwargs,767        )768769    def on_llm_error(770        self,771        error: BaseException,772        **kwargs: Any,773    ) -> None:774        """Run when LLM errors.775776        Args:777            error: The error.778            **kwargs: Additional keyword arguments.779780                - response (LLMResult): The response which was generated before781                    the error occurred.782        """783        if not self.handlers:784            return785        handle_event(786            self.handlers,787            "on_llm_error",788            "ignore_llm",789            error,790            run_id=self.run_id,791            parent_run_id=self.parent_run_id,792            tags=self.tags,793            **kwargs,794        )795796    def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:797        """Run on each protocol event from `stream_events(version="v3")`.798799        Args:800            event: The protocol event.801            **kwargs: Additional keyword arguments.802        """803        if not self.handlers:804            return805        handle_event(806            self.handlers,807            "on_stream_event",808            "ignore_llm",809            event,810            run_id=self.run_id,811            parent_run_id=self.parent_run_id,812            tags=self.tags,813            **kwargs,814        )815816817class AsyncCallbackManagerForLLMRun(AsyncRunManager, LLMManagerMixin):818    """Async callback manager for LLM run."""819820    def get_sync(self) -> CallbackManagerForLLMRun:821        """Get the equivalent sync `RunManager`.822823        Returns:824            The sync `RunManager`.825826        """827        return CallbackManagerForLLMRun(828            run_id=self.run_id,829            handlers=self.handlers,830            inheritable_handlers=self.inheritable_handlers,831            parent_run_id=self.parent_run_id,832            tags=self.tags,833            inheritable_tags=self.inheritable_tags,834            metadata=self.metadata,835            inheritable_metadata=self.inheritable_metadata,836        )837838    async def on_llm_new_token(839        self,840        token: str | list[str | dict[str, Any]],841        *,842        chunk: GenerationChunk | ChatGenerationChunk | None = None,843        **kwargs: Any,844    ) -> None:845        """Run when LLM generates a new token.846847        Args:848            token: The new token, or a list of content blocks.849            chunk: The chunk.850            **kwargs: Additional keyword arguments.851852        """853        if not self.handlers:854            return855        await ahandle_event(856            self.handlers,857            "on_llm_new_token",858            "ignore_llm",859            token,860            chunk=chunk,861            run_id=self.run_id,862            parent_run_id=self.parent_run_id,863            tags=self.tags,864            **kwargs,865        )866867    @shielded868    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:869        """Run when LLM ends running.870871        Args:872            response: The LLM result.873            **kwargs: Additional keyword arguments.874875        """876        if not self.handlers:877            return878        await ahandle_event(879            self.handlers,880            "on_llm_end",881            "ignore_llm",882            response,883            run_id=self.run_id,884            parent_run_id=self.parent_run_id,885            tags=self.tags,886            **kwargs,887        )888889    @shielded890    async def on_llm_error(891        self,892        error: BaseException,893        **kwargs: Any,894    ) -> None:895        """Run when LLM errors.896897        Args:898            error: The error.899            **kwargs: Additional keyword arguments.900901                - response (LLMResult): The response which was generated before902                    the error occurred.903904        """905        if not self.handlers:906            return907        await ahandle_event(908            self.handlers,909            "on_llm_error",910            "ignore_llm",911            error,912            run_id=self.run_id,913            parent_run_id=self.parent_run_id,914            tags=self.tags,915            **kwargs,916        )917918    async def on_stream_event(self, event: MessagesData, **kwargs: Any) -> None:919        """Run on each protocol event from `astream_events(version="v3")`.920921        Args:922            event: The protocol event.923            **kwargs: Additional keyword arguments.924        """925        if not self.handlers:926            return927        await ahandle_event(928            self.handlers,929            "on_stream_event",930            "ignore_llm",931            event,932            run_id=self.run_id,933            parent_run_id=self.parent_run_id,934            tags=self.tags,935            **kwargs,936        )937938939class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):940    """Callback manager for chain run."""941942    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:943        """Run when chain ends running.944945        Args:946            outputs: The outputs of the chain.947            **kwargs: Additional keyword arguments.948949        """950        if not self.handlers:951            return952        handle_event(953            self.handlers,954            "on_chain_end",955            "ignore_chain",956            outputs,957            run_id=self.run_id,958            parent_run_id=self.parent_run_id,959            tags=self.tags,960            **kwargs,961        )962963    def on_chain_error(964        self,965        error: BaseException,966        **kwargs: Any,967    ) -> None:968        """Run when chain errors.969970        Args:971            error: The error.972            **kwargs: Additional keyword arguments.973974        """975        if not self.handlers:976            return977        handle_event(978            self.handlers,979            "on_chain_error",980            "ignore_chain",981            error,982            run_id=self.run_id,983            parent_run_id=self.parent_run_id,984            tags=self.tags,985            **kwargs,986        )987988    def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:989        """Run when agent action is received.990991        Args:992            action: The agent action.993            **kwargs: Additional keyword arguments.994        """995        if not self.handlers:996            return997        handle_event(998            self.handlers,999            "on_agent_action",1000            "ignore_agent",1001            action,1002            run_id=self.run_id,1003            parent_run_id=self.parent_run_id,1004            tags=self.tags,1005            **kwargs,1006        )10071008    def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:1009        """Run when agent finish is received.10101011        Args:1012            finish: The agent finish.1013            **kwargs: Additional keyword arguments.1014        """1015        if not self.handlers:1016            return1017        handle_event(1018            self.handlers,1019            "on_agent_finish",1020            "ignore_agent",1021            finish,1022            run_id=self.run_id,1023            parent_run_id=self.parent_run_id,1024            tags=self.tags,1025            **kwargs,1026        )102710281029class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):1030    """Async callback manager for chain run."""10311032    def get_sync(self) -> CallbackManagerForChainRun:1033        """Get the equivalent sync `RunManager`.10341035        Returns:1036            The sync `RunManager`.1037        """1038        return CallbackManagerForChainRun(1039            run_id=self.run_id,1040            handlers=self.handlers,1041            inheritable_handlers=self.inheritable_handlers,1042            parent_run_id=self.parent_run_id,1043            tags=self.tags,1044            inheritable_tags=self.inheritable_tags,1045            metadata=self.metadata,1046            inheritable_metadata=self.inheritable_metadata,1047        )10481049    @shielded1050    async def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1051        """Run when a chain ends running.10521053        Args:1054            outputs: The outputs of the chain.1055            **kwargs: Additional keyword arguments.10561057        """1058        if not self.handlers:1059            return1060        await ahandle_event(1061            self.handlers,1062            "on_chain_end",1063            "ignore_chain",1064            outputs,1065            run_id=self.run_id,1066            parent_run_id=self.parent_run_id,1067            tags=self.tags,1068            **kwargs,1069        )10701071    @shielded1072    async def on_chain_error(1073        self,1074        error: BaseException,1075        **kwargs: Any,1076    ) -> None:1077        """Run when chain errors.10781079        Args:1080            error: The error.1081            **kwargs: Additional keyword arguments.10821083        """1084        if not self.handlers:1085            return1086        await ahandle_event(1087            self.handlers,1088            "on_chain_error",1089            "ignore_chain",1090            error,1091            run_id=self.run_id,1092            parent_run_id=self.parent_run_id,1093            tags=self.tags,1094            **kwargs,1095        )10961097    async def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:1098        """Run when agent action is received.10991100        Args:1101            action: The agent action.1102            **kwargs: Additional keyword arguments.1103        """1104        if not self.handlers:1105            return1106        await ahandle_event(1107            self.handlers,1108            "on_agent_action",1109            "ignore_agent",1110            action,1111            run_id=self.run_id,1112            parent_run_id=self.parent_run_id,1113            tags=self.tags,1114            **kwargs,1115        )11161117    async def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:1118        """Run when agent finish is received.11191120        Args:1121            finish: The agent finish.1122            **kwargs: Additional keyword arguments.1123        """1124        if not self.handlers:1125            return1126        await ahandle_event(1127            self.handlers,1128            "on_agent_finish",1129            "ignore_agent",1130            finish,1131            run_id=self.run_id,1132            parent_run_id=self.parent_run_id,1133            tags=self.tags,1134            **kwargs,1135        )113611371138class CallbackManagerForToolRun(ParentRunManager, ToolManagerMixin):1139    """Callback manager for tool run."""11401141    def on_tool_end(1142        self,1143        output: Any,1144        **kwargs: Any,1145    ) -> None:1146        """Run when the tool ends running.11471148        Args:1149            output: The output of the tool.1150            **kwargs: The keyword arguments to pass to the event handler11511152        """1153        if not self.handlers:1154            return1155        handle_event(1156            self.handlers,1157            "on_tool_end",1158            "ignore_agent",1159            output,1160            run_id=self.run_id,1161            parent_run_id=self.parent_run_id,1162            tags=self.tags,1163            **kwargs,1164        )11651166    def on_tool_error(1167        self,1168        error: BaseException,1169        **kwargs: Any,1170    ) -> None:1171        """Run when tool errors.11721173        Args:1174            error: The error.1175            **kwargs: Additional keyword arguments.11761177        """1178        if not self.handlers:1179            return1180        handle_event(1181            self.handlers,1182            "on_tool_error",1183            "ignore_agent",1184            error,1185            run_id=self.run_id,1186            parent_run_id=self.parent_run_id,1187            tags=self.tags,1188            **kwargs,1189        )119011911192class AsyncCallbackManagerForToolRun(AsyncParentRunManager, ToolManagerMixin):1193    """Async callback manager for tool run."""11941195    def get_sync(self) -> CallbackManagerForToolRun:1196        """Get the equivalent sync `RunManager`.11971198        Returns:1199            The sync `RunManager`.1200        """1201        return CallbackManagerForToolRun(1202            run_id=self.run_id,1203            handlers=self.handlers,1204            inheritable_handlers=self.inheritable_handlers,1205            parent_run_id=self.parent_run_id,1206            tags=self.tags,1207            inheritable_tags=self.inheritable_tags,1208            metadata=self.metadata,1209            inheritable_metadata=self.inheritable_metadata,1210        )12111212    async def on_tool_end(self, output: Any, **kwargs: Any) -> None:1213        """Async run when the tool ends running.12141215        Args:1216            output: The output of the tool.1217            **kwargs: Additional keyword arguments.12181219        """1220        if not self.handlers:1221            return1222        await ahandle_event(1223            self.handlers,1224            "on_tool_end",1225            "ignore_agent",1226            output,1227            run_id=self.run_id,1228            parent_run_id=self.parent_run_id,1229            tags=self.tags,1230            **kwargs,1231        )12321233    async def on_tool_error(1234        self,1235        error: BaseException,1236        **kwargs: Any,1237    ) -> None:1238        """Run when tool errors.12391240        Args:1241            error: The error.1242            **kwargs: Additional keyword arguments.12431244        """1245        if not self.handlers:1246            return1247        await ahandle_event(1248            self.handlers,1249            "on_tool_error",1250            "ignore_agent",1251            error,1252            run_id=self.run_id,1253            parent_run_id=self.parent_run_id,1254            tags=self.tags,1255            **kwargs,1256        )125712581259class CallbackManagerForRetrieverRun(ParentRunManager, RetrieverManagerMixin):1260    """Callback manager for retriever run."""12611262    def on_retriever_end(1263        self,1264        documents: Sequence[Document],1265        **kwargs: Any,1266    ) -> None:1267        """Run when retriever ends running.12681269        Args:1270            documents: The retrieved documents.1271            **kwargs: Additional keyword arguments.12721273        """1274        if not self.handlers:1275            return1276        handle_event(1277            self.handlers,1278            "on_retriever_end",1279            "ignore_retriever",1280            documents,1281            run_id=self.run_id,1282            parent_run_id=self.parent_run_id,1283            tags=self.tags,1284            **kwargs,1285        )12861287    def on_retriever_error(1288        self,1289        error: BaseException,1290        **kwargs: Any,1291    ) -> None:1292        """Run when retriever errors.12931294        Args:1295            error: The error.1296            **kwargs: Additional keyword arguments.12971298        """1299        if not self.handlers:1300            return1301        handle_event(1302            self.handlers,1303            "on_retriever_error",1304            "ignore_retriever",1305            error,1306            run_id=self.run_id,1307            parent_run_id=self.parent_run_id,1308            tags=self.tags,1309            **kwargs,1310        )131113121313class AsyncCallbackManagerForRetrieverRun(1314    AsyncParentRunManager,1315    RetrieverManagerMixin,1316):1317    """Async callback manager for retriever run."""13181319    def get_sync(self) -> CallbackManagerForRetrieverRun:1320        """Get the equivalent sync `RunManager`.13211322        Returns:1323            The sync `RunManager`.13241325        """1326        return CallbackManagerForRetrieverRun(1327            run_id=self.run_id,1328            handlers=self.handlers,1329            inheritable_handlers=self.inheritable_handlers,1330            parent_run_id=self.parent_run_id,1331            tags=self.tags,1332            inheritable_tags=self.inheritable_tags,1333            metadata=self.metadata,1334            inheritable_metadata=self.inheritable_metadata,1335        )13361337    @shielded1338    async def on_retriever_end(1339        self, documents: Sequence[Document], **kwargs: Any1340    ) -> None:1341        """Run when the retriever ends running.13421343        Args:1344            documents: The retrieved documents.1345            **kwargs: Additional keyword arguments.13461347        """1348        if not self.handlers:1349            return1350        await ahandle_event(1351            self.handlers,1352            "on_retriever_end",1353            "ignore_retriever",1354            documents,1355            run_id=self.run_id,1356            parent_run_id=self.parent_run_id,1357            tags=self.tags,1358            **kwargs,1359        )13601361    @shielded1362    async def on_retriever_error(1363        self,1364        error: BaseException,1365        **kwargs: Any,1366    ) -> None:1367        """Run when retriever errors.13681369        Args:1370            error: The error.1371            **kwargs: Additional keyword arguments.13721373        """1374        if not self.handlers:1375            return1376        await ahandle_event(1377            self.handlers,1378            "on_retriever_error",1379            "ignore_retriever",1380            error,1381            run_id=self.run_id,1382            parent_run_id=self.parent_run_id,1383            tags=self.tags,1384            **kwargs,1385        )138613871388class CallbackManager(BaseCallbackManager):1389    """Callback manager for LangChain."""13901391    def on_llm_start(1392        self,1393        serialized: dict[str, Any],1394        prompts: list[str],1395        run_id: UUID | None = None,1396        **kwargs: Any,1397    ) -> list[CallbackManagerForLLMRun]:1398        """Run when LLM starts running.13991400        Args:1401            serialized: The serialized LLM.1402            prompts: The list of prompts.1403            run_id: The ID of the run.1404            **kwargs: Additional keyword arguments.14051406        Returns:1407            A callback manager for each prompt as an LLM run.14081409        """1410        managers = []1411        for i, prompt in enumerate(prompts):1412            # Can't have duplicate runs with the same run ID (if provided)1413            run_id_ = run_id if i == 0 and run_id is not None else uuid7()1414            handle_event(1415                self.handlers,1416                "on_llm_start",1417                "ignore_llm",1418                serialized,1419                [prompt],1420                run_id=run_id_,1421                parent_run_id=self.parent_run_id,1422                tags=self.tags,1423                metadata=self.metadata,1424                **kwargs,1425            )14261427            managers.append(1428                CallbackManagerForLLMRun(1429                    run_id=run_id_,1430                    handlers=self.handlers,1431                    inheritable_handlers=self.inheritable_handlers,1432                    parent_run_id=self.parent_run_id,1433                    tags=self.tags,1434                    inheritable_tags=self.inheritable_tags,1435                    metadata=self.metadata,1436                    inheritable_metadata=self.inheritable_metadata,1437                )1438            )14391440        return managers14411442    def on_chat_model_start(1443        self,1444        serialized: dict[str, Any],1445        messages: list[list[BaseMessage]],1446        run_id: UUID | None = None,1447        **kwargs: Any,1448    ) -> list[CallbackManagerForLLMRun]:1449        """Run when chat model starts running.14501451        Args:1452            serialized: The serialized LLM.1453            messages: The list of messages.1454            run_id: The ID of the run.1455            **kwargs: Additional keyword arguments.14561457        Returns:1458            A callback manager for each list of messages as an LLM run.14591460        """1461        managers = []1462        for message_list in messages:1463            if run_id is not None:1464                run_id_ = run_id1465                run_id = None1466            else:1467                run_id_ = uuid7()1468            handle_event(1469                self.handlers,1470                "on_chat_model_start",1471                "ignore_chat_model",1472                serialized,1473                [message_list],1474                run_id=run_id_,1475                parent_run_id=self.parent_run_id,1476                tags=self.tags,1477                metadata=self.metadata,1478                **kwargs,1479            )14801481            managers.append(1482                CallbackManagerForLLMRun(1483                    run_id=run_id_,1484                    handlers=self.handlers,1485                    inheritable_handlers=self.inheritable_handlers,1486                    parent_run_id=self.parent_run_id,1487                    tags=self.tags,1488                    inheritable_tags=self.inheritable_tags,1489                    metadata=self.metadata,1490                    inheritable_metadata=self.inheritable_metadata,1491                )1492            )14931494        return managers14951496    def on_chain_start(1497        self,1498        serialized: dict[str, Any] | None,1499        inputs: dict[str, Any] | Any,1500        run_id: UUID | None = None,1501        **kwargs: Any,1502    ) -> CallbackManagerForChainRun:1503        """Run when chain starts running.15041505        Args:1506            serialized: The serialized chain.1507            inputs: The inputs to the chain.1508            run_id: The ID of the run.1509            **kwargs: Additional keyword arguments.15101511        Returns:1512            The callback manager for the chain run.15131514        """1515        if run_id is None:1516            run_id = uuid7()1517        handle_event(1518            self.handlers,1519            "on_chain_start",1520            "ignore_chain",1521            serialized,1522            inputs,1523            run_id=run_id,1524            parent_run_id=self.parent_run_id,1525            tags=self.tags,1526            metadata=self.metadata,1527            **kwargs,1528        )15291530        return CallbackManagerForChainRun(1531            run_id=run_id,1532            handlers=self.handlers,1533            inheritable_handlers=self.inheritable_handlers,1534            parent_run_id=self.parent_run_id,1535            tags=self.tags,1536            inheritable_tags=self.inheritable_tags,1537            metadata=self.metadata,1538            inheritable_metadata=self.inheritable_metadata,1539        )15401541    @override1542    def on_tool_start(1543        self,1544        serialized: dict[str, Any] | None,1545        input_str: str,1546        run_id: UUID | None = None,1547        parent_run_id: UUID | None = None,1548        inputs: dict[str, Any] | None = None,1549        **kwargs: Any,1550    ) -> CallbackManagerForToolRun:1551        """Run when tool starts running.15521553        Args:1554            serialized: Serialized representation of the tool.1555            input_str: The  input to the tool as a string.15561557                Non-string inputs are cast to strings.1558            run_id: ID for the run.1559            parent_run_id: The ID of the parent run.1560            inputs: The original input to the tool if provided.15611562                Recommended for usage instead of input_str when the original input is1563                needed.15641565                If provided, the inputs are expected to be formatted as a dict. The keys1566                will correspond to the named-arguments in the tool.1567            **kwargs: The keyword arguments to pass to the event handler15681569        Returns:1570            The callback manager for the tool run.15711572        """1573        if run_id is None:1574            run_id = uuid7()15751576        handle_event(1577            self.handlers,1578            "on_tool_start",1579            "ignore_agent",1580            serialized,1581            input_str,1582            run_id=run_id,1583            parent_run_id=self.parent_run_id,1584            tags=self.tags,1585            metadata=self.metadata,1586            inputs=inputs,1587            **kwargs,1588        )15891590        return CallbackManagerForToolRun(1591            run_id=run_id,1592            handlers=self.handlers,1593            inheritable_handlers=self.inheritable_handlers,1594            parent_run_id=self.parent_run_id,1595            tags=self.tags,1596            inheritable_tags=self.inheritable_tags,1597            metadata=self.metadata,1598            inheritable_metadata=self.inheritable_metadata,1599        )16001601    @override1602    def on_retriever_start(1603        self,1604        serialized: dict[str, Any] | None,1605        query: str,1606        run_id: UUID | None = None,1607        parent_run_id: UUID | None = None,1608        **kwargs: Any,1609    ) -> CallbackManagerForRetrieverRun:1610        """Run when the retriever starts running.16111612        Args:1613            serialized: The serialized retriever.1614            query: The query.1615            run_id: The ID of the run.1616            parent_run_id: The ID of the parent run.1617            **kwargs: Additional keyword arguments.16181619        Returns:1620            The callback manager for the retriever run.1621        """1622        if run_id is None:1623            run_id = uuid7()16241625        handle_event(1626            self.handlers,1627            "on_retriever_start",1628            "ignore_retriever",1629            serialized,1630            query,1631            run_id=run_id,1632            parent_run_id=self.parent_run_id,1633            tags=self.tags,1634            metadata=self.metadata,1635            **kwargs,1636        )16371638        return CallbackManagerForRetrieverRun(1639            run_id=run_id,1640            handlers=self.handlers,1641            inheritable_handlers=self.inheritable_handlers,1642            parent_run_id=self.parent_run_id,1643            tags=self.tags,1644            inheritable_tags=self.inheritable_tags,1645            metadata=self.metadata,1646            inheritable_metadata=self.inheritable_metadata,1647        )16481649    def on_custom_event(1650        self,1651        name: str,1652        data: Any,1653        run_id: UUID | None = None,1654        **kwargs: Any,1655    ) -> None:1656        """Dispatch an adhoc event to the handlers (async version).16571658        This event should NOT be used in any internal LangChain code. The event is meant1659        specifically for users of the library to dispatch custom events that are1660        tailored to their application.16611662        Args:1663            name: The name of the adhoc event.1664            data: The data for the adhoc event.1665            run_id: The ID of the run.16661667        Raises:1668            ValueError: If additional keyword arguments are passed.1669        """1670        if not self.handlers:1671            return1672        if kwargs:1673            msg = (1674                "The dispatcher API does not accept additional keyword arguments."1675                "Please do not pass any additional keyword arguments, instead "1676                "include them in the data field."1677            )1678            raise ValueError(msg)1679        if run_id is None:1680            run_id = uuid7()16811682        handle_event(1683            self.handlers,1684            "on_custom_event",1685            "ignore_custom_event",1686            name,1687            data,1688            run_id=run_id,1689            tags=self.tags,1690            metadata=self.metadata,1691        )16921693    @classmethod1694    def configure(1695        cls,1696        inheritable_callbacks: Callbacks = None,1697        local_callbacks: Callbacks = None,1698        verbose: bool = False,  # noqa: FBT001,FBT0021699        inheritable_tags: list[str] | None = None,1700        local_tags: list[str] | None = None,1701        inheritable_metadata: dict[str, Any] | None = None,1702        local_metadata: dict[str, Any] | None = None,1703        *,1704        langsmith_inheritable_metadata: Mapping[str, Any] | None = None,1705        langsmith_inheritable_tags: list[str] | None = None,1706    ) -> CallbackManager:1707        """Configure the callback manager.17081709        Args:1710            inheritable_callbacks: The inheritable callbacks.1711            local_callbacks: The local callbacks.1712            verbose: Whether to enable verbose mode.1713            inheritable_tags: The inheritable tags.1714            local_tags: The local tags.1715            inheritable_metadata: The inheritable metadata.1716            local_metadata: The local metadata.1717            langsmith_inheritable_metadata: Default inheritable metadata applied1718                to any `LangChainTracer` handlers via `set_defaults`.1719            langsmith_inheritable_tags: Default inheritable tags applied to any1720                `LangChainTracer` handlers via `set_defaults`.17211722        Returns:1723            The configured callback manager.1724        """1725        return _configure(1726            cls,1727            inheritable_callbacks,1728            local_callbacks,1729            inheritable_tags,1730            local_tags,1731            inheritable_metadata,1732            local_metadata,1733            verbose=verbose,1734            langsmith_inheritable_metadata=langsmith_inheritable_metadata,1735            langsmith_inheritable_tags=langsmith_inheritable_tags,1736        )173717381739class CallbackManagerForChainGroup(CallbackManager):1740    """Callback manager for the chain group."""17411742    def __init__(1743        self,1744        handlers: list[BaseCallbackHandler],1745        inheritable_handlers: list[BaseCallbackHandler] | None = None,1746        parent_run_id: UUID | None = None,1747        *,1748        parent_run_manager: CallbackManagerForChainRun,1749        **kwargs: Any,1750    ) -> None:1751        """Initialize the callback manager.17521753        Args:1754            handlers: The list of handlers.1755            inheritable_handlers: The list of inheritable handlers.1756            parent_run_id: The ID of the parent run.1757            parent_run_manager: The parent run manager.1758            **kwargs: Additional keyword arguments.17591760        """1761        super().__init__(1762            handlers,1763            inheritable_handlers,1764            parent_run_id,1765            **kwargs,1766        )1767        self.parent_run_manager = parent_run_manager1768        self.ended = False17691770    @override1771    def copy(self) -> CallbackManagerForChainGroup:1772        return self.__class__(1773            handlers=self.handlers.copy(),1774            inheritable_handlers=self.inheritable_handlers.copy(),1775            parent_run_id=self.parent_run_id,1776            tags=self.tags.copy(),1777            inheritable_tags=self.inheritable_tags.copy(),1778            metadata=self.metadata.copy(),1779            inheritable_metadata=self.inheritable_metadata.copy(),1780            parent_run_manager=self.parent_run_manager,1781        )17821783    def merge(1784        self: CallbackManagerForChainGroup, other: BaseCallbackManager1785    ) -> CallbackManagerForChainGroup:1786        """Merge the group callback manager with another callback manager.17871788        Overwrites the merge method in the base class to ensure that the parent run1789        manager is preserved. Keeps the `parent_run_manager` from the current object.17901791        Returns:1792            A copy of the current object with the handlers, tags, and other attributes1793            merged from the other object.17941795        Example:1796            ```python1797            # Merging two callback managers1798            from langchain_core.callbacks.manager import (1799                CallbackManager,1800                trace_as_chain_group,1801            )1802            from langchain_core.callbacks.stdout import StdOutCallbackHandler18031804            manager = CallbackManager(handlers=[StdOutCallbackHandler()], tags=["tag2"])1805            with trace_as_chain_group("My Group Name", tags=["tag1"]) as group_manager:1806                merged_manager = group_manager.merge(manager)1807                print(type(merged_manager))1808                # <class 'langchain_core.callbacks.manager.CallbackManagerForChainGroup'>18091810                print(merged_manager.handlers)1811                # [1812                #    <langchain_core.callbacks.stdout.LangChainTracer object at ...>,1813                #    <langchain_core.callbacks.streaming_stdout.StdOutCallbackHandler object at ...>,1814                # ]18151816                print(merged_manager.tags)1817                #    ['tag2', 'tag1']1818            ```1819        """  # noqa: E5011820        manager = self.__class__(1821            parent_run_id=self.parent_run_id or other.parent_run_id,1822            handlers=[],1823            inheritable_handlers=[],1824            tags=list(set(self.tags + other.tags)),1825            inheritable_tags=list(set(self.inheritable_tags + other.inheritable_tags)),1826            metadata={1827                **self.metadata,1828                **other.metadata,1829            },1830            parent_run_manager=self.parent_run_manager,1831        )18321833        handlers = self.handlers + other.handlers1834        inheritable_handlers = self.inheritable_handlers + other.inheritable_handlers18351836        for handler in handlers:1837            manager.add_handler(handler)18381839        for handler in inheritable_handlers:1840            manager.add_handler(handler, inherit=True)1841        return manager18421843    def on_chain_end(self, outputs: dict[str, Any] | Any, **kwargs: Any) -> None:1844        """Run when traced chain group ends.18451846        Args:1847            outputs: The outputs of the chain.1848            **kwargs: Additional keyword arguments.18491850        """1851        self.ended = True1852        return self.parent_run_manager.on_chain_end(outputs, **kwargs)18531854    def on_chain_error(1855        self,1856        error: BaseException,1857        **kwargs: Any,1858    ) -> None:1859        """Run when chain errors.18601861        Args:1862            error: The error.1863            **kwargs: Additional keyword arguments.18641865        """1866        self.ended = True1867        return self.parent_run_manager.on_chain_error(error, **kwargs)186818691870class AsyncCallbackManager(BaseCallbackManager):1871    """Async callback manager that handles callbacks from LangChain."""18721873    @property1874    def is_async(self) -> bool:1875        """Return whether the handler is async."""1876        return True18771878    async def on_llm_start(1879        self,1880        serialized: dict[str, Any],1881        prompts: list[str],1882        run_id: UUID | None = None,1883        **kwargs: Any,1884    ) -> list[AsyncCallbackManagerForLLMRun]:1885        """Run when LLM starts running.18861887        Args:1888            serialized: The serialized LLM.1889            prompts: The list of prompts.1890            run_id: The ID of the run.1891            **kwargs: Additional keyword arguments.18921893        Returns:1894            The list of async callback managers, one for each LLM run corresponding to1895            each prompt.1896        """1897        inline_tasks = []1898        non_inline_tasks = []1899        inline_handlers = [handler for handler in self.handlers if handler.run_inline]1900        non_inline_handlers = [1901            handler for handler in self.handlers if not handler.run_inline1902        ]1903        managers = []19041905        for prompt in prompts:1906            if run_id is not None:1907                run_id_ = run_id1908                run_id = None1909            else:1910                run_id_ = uuid7()19111912            if inline_handlers:1913                inline_tasks.append(1914                    ahandle_event(1915                        inline_handlers,1916                        "on_llm_start",1917                        "ignore_llm",1918                        serialized,1919                        [prompt],1920                        run_id=run_id_,1921                        parent_run_id=self.parent_run_id,1922                        tags=self.tags,1923                        metadata=self.metadata,1924                        **kwargs,1925                    )1926                )1927            else:1928                non_inline_tasks.append(1929                    ahandle_event(1930                        non_inline_handlers,1931                        "on_llm_start",1932                        "ignore_llm",1933                        serialized,1934                        [prompt],1935                        run_id=run_id_,1936                        parent_run_id=self.parent_run_id,1937                        tags=self.tags,1938                        metadata=self.metadata,1939                        **kwargs,1940                    )1941                )19421943            managers.append(1944                AsyncCallbackManagerForLLMRun(1945                    run_id=run_id_,1946                    handlers=self.handlers,1947                    inheritable_handlers=self.inheritable_handlers,1948                    parent_run_id=self.parent_run_id,1949                    tags=self.tags,1950                    inheritable_tags=self.inheritable_tags,1951                    metadata=self.metadata,1952                    inheritable_metadata=self.inheritable_metadata,1953                )1954            )19551956        # Run inline tasks sequentially1957        for inline_task in inline_tasks:1958            await inline_task19591960        # Run non-inline tasks concurrently1961        if non_inline_tasks:1962            await asyncio.gather(*non_inline_tasks)19631964        return managers19651966    async def on_chat_model_start(1967        self,1968        serialized: dict[str, Any],1969        messages: list[list[BaseMessage]],1970        run_id: UUID | None = None,1971        **kwargs: Any,1972    ) -> list[AsyncCallbackManagerForLLMRun]:1973        """Async run when LLM starts running.19741975        Args:1976            serialized: The serialized LLM.1977            messages: The list of messages.1978            run_id: The ID of the run.1979            **kwargs: Additional keyword arguments.19801981        Returns:1982            The list of async callback managers, one for each LLM run corresponding to1983            each inner message list.1984        """1985        inline_tasks = []1986        non_inline_tasks = []1987        managers = []19881989        for message_list in messages:1990            if run_id is not None:1991                run_id_ = run_id1992                run_id = None1993            else:1994                run_id_ = uuid7()19951996            for handler in self.handlers:1997                task = ahandle_event(1998                    [handler],1999                    "on_chat_model_start",2000                    "ignore_chat_model",

Code quality findings 2

Ensure functions have docstrings for documentation
info maintainability missing-docstring
async def wrapped(*args: Any, **kwargs: Any) -> Any:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def copy(self) -> CallbackManagerForChainGroup:

Get this view in your editor

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

Generated by searchcode.com · powered by code_get_file + code_get_findings