libs/core/langchain_core/callbacks/base.py PYTHON 1,224 lines View on github.com → Search inside
1"""Base callback handler for LangChain."""23from __future__ import annotations45import logging6from typing import TYPE_CHECKING, Any78if TYPE_CHECKING:9    from collections.abc import Sequence10    from uuid import UUID1112    from langchain_protocol.protocol import MessagesData13    from tenacity import RetryCallState14    from typing_extensions import Self1516    from langchain_core.agents import AgentAction, AgentFinish17    from langchain_core.documents import Document18    from langchain_core.messages import BaseMessage19    from langchain_core.outputs import ChatGenerationChunk, GenerationChunk, LLMResult2021_LOGGER = logging.getLogger(__name__)222324class RetrieverManagerMixin:25    """Mixin for `Retriever` callbacks."""2627    def on_retriever_error(28        self,29        error: BaseException,30        *,31        run_id: UUID,32        parent_run_id: UUID | None = None,33        **kwargs: Any,34    ) -> Any:35        """Run when `Retriever` errors.3637        Args:38            error: The error that occurred.39            run_id: The ID of the current run.40            parent_run_id: The ID of the parent run.41            **kwargs: Additional keyword arguments.42        """4344    def on_retriever_end(45        self,46        documents: Sequence[Document],47        *,48        run_id: UUID,49        parent_run_id: UUID | None = None,50        **kwargs: Any,51    ) -> Any:52        """Run when `Retriever` ends running.5354        Args:55            documents: The documents retrieved.56            run_id: The ID of the current run.57            parent_run_id: The ID of the parent run.58            **kwargs: Additional keyword arguments.59        """606162class LLMManagerMixin:63    """Mixin for LLM callbacks."""6465    def on_llm_new_token(66        self,67        token: str,68        *,69        chunk: GenerationChunk | ChatGenerationChunk | None = None,70        run_id: UUID,71        parent_run_id: UUID | None = None,72        tags: list[str] | None = None,73        **kwargs: Any,74    ) -> Any:75        """Run on new output token.7677        Only available when streaming is enabled.7879        For both chat models and non-chat models (legacy text completion LLMs).8081        Args:82            token: The new token.83            chunk: The new generated chunk, containing content and other information.84            run_id: The ID of the current run.85            parent_run_id: The ID of the parent run.86            tags: The tags.87            **kwargs: Additional keyword arguments.88        """8990    def on_llm_end(91        self,92        response: LLMResult,93        *,94        run_id: UUID,95        parent_run_id: UUID | None = None,96        tags: list[str] | None = None,97        **kwargs: Any,98    ) -> Any:99        """Run when LLM ends running.100101        Args:102            response: The response which was generated.103            run_id: The ID of the current run.104            parent_run_id: The ID of the parent run.105            tags: The tags.106            **kwargs: Additional keyword arguments.107        """108109    def on_llm_error(110        self,111        error: BaseException,112        *,113        run_id: UUID,114        parent_run_id: UUID | None = None,115        tags: list[str] | None = None,116        **kwargs: Any,117    ) -> Any:118        """Run when LLM errors.119120        Args:121            error: The error that occurred.122            run_id: The ID of the current run.123            parent_run_id: The ID of the parent run.124            tags: The tags.125            **kwargs: Additional keyword arguments.126        """127128    def on_stream_event(129        self,130        event: MessagesData,131        *,132        run_id: UUID,133        parent_run_id: UUID | None = None,134        tags: list[str] | None = None,135        **kwargs: Any,136    ) -> Any:137        """Run on each protocol event from `stream_events(version="v3")`.138139        Also fires for the async equivalent140        (`astream_events(version="v3")`).141142        Fires once per `MessagesData` event  `message-start`, per-block143        `content-block-start` / `content-block-delta` /144        `content-block-finish`, and `message-finish`. Analogous to145        `on_llm_new_token` in v1 streaming, but at event granularity rather146        than chunk: a single chunk can map to multiple events (e.g. a147        `content-block-start` plus its first `content-block-delta`), and148        lifecycle boundaries are explicit.149150        Fires uniformly whether the provider emits events natively via151        `_stream_chat_model_events` or goes through the chunk-to-event152        compat bridge. Observers see the same event stream regardless of153        how the underlying model produces output.154155        Not fired from v1 `stream()` / `astream()`; for those, keep using156        `on_llm_new_token`. Purely additive  `on_chat_model_start`,157        `on_llm_end`, and `on_llm_error` still fire around a v2 call as158        they do around a v1 call.159160        Args:161            event: The protocol event.162            run_id: The ID of the current run.163            parent_run_id: The ID of the parent run.164            tags: The tags.165            **kwargs: Additional keyword arguments.166        """167168169class ChainManagerMixin:170    """Mixin for chain callbacks."""171172    def on_chain_end(173        self,174        outputs: dict[str, Any],175        *,176        run_id: UUID,177        parent_run_id: UUID | None = None,178        **kwargs: Any,179    ) -> Any:180        """Run when chain ends running.181182        Args:183            outputs: The outputs of the chain.184            run_id: The ID of the current run.185            parent_run_id: The ID of the parent run.186            **kwargs: Additional keyword arguments.187        """188189    def on_chain_error(190        self,191        error: BaseException,192        *,193        run_id: UUID,194        parent_run_id: UUID | None = None,195        **kwargs: Any,196    ) -> Any:197        """Run when chain errors.198199        Args:200            error: The error that occurred.201            run_id: The ID of the current run.202            parent_run_id: The ID of the parent run.203            **kwargs: Additional keyword arguments.204        """205206    def on_agent_action(207        self,208        action: AgentAction,209        *,210        run_id: UUID,211        parent_run_id: UUID | None = None,212        **kwargs: Any,213    ) -> Any:214        """Run on agent action.215216        Args:217            action: The agent action.218            run_id: The ID of the current run.219            parent_run_id: The ID of the parent run.220            **kwargs: Additional keyword arguments.221        """222223    def on_agent_finish(224        self,225        finish: AgentFinish,226        *,227        run_id: UUID,228        parent_run_id: UUID | None = None,229        **kwargs: Any,230    ) -> Any:231        """Run on the agent end.232233        Args:234            finish: The agent finish.235            run_id: The ID of the current run.236            parent_run_id: The ID of the parent run.237            **kwargs: Additional keyword arguments.238        """239240241class ToolManagerMixin:242    """Mixin for tool callbacks."""243244    def on_tool_end(245        self,246        output: Any,247        *,248        run_id: UUID,249        parent_run_id: UUID | None = None,250        **kwargs: Any,251    ) -> Any:252        """Run when the tool ends running.253254        Args:255            output: The output of the tool.256            run_id: The ID of the current run.257            parent_run_id: The ID of the parent run.258            **kwargs: Additional keyword arguments.259        """260261    def on_tool_error(262        self,263        error: BaseException,264        *,265        run_id: UUID,266        parent_run_id: UUID | None = None,267        **kwargs: Any,268    ) -> Any:269        """Run when tool errors.270271        Args:272            error: The error that occurred.273            run_id: The ID of the current run.274            parent_run_id: The ID of the parent run.275            **kwargs: Additional keyword arguments.276        """277278279class CallbackManagerMixin:280    """Mixin for callback manager."""281282    def on_llm_start(283        self,284        serialized: dict[str, Any],285        prompts: list[str],286        *,287        run_id: UUID,288        parent_run_id: UUID | None = None,289        tags: list[str] | None = None,290        metadata: dict[str, Any] | None = None,291        **kwargs: Any,292    ) -> Any:293        """Run when LLM starts running.294295        !!! warning296297            This method is called for non-chat models (regular text completion LLMs). If298            you're implementing a handler for a chat model, you should use299            `on_chat_model_start` instead.300301        Args:302            serialized: The serialized LLM.303            prompts: The prompts.304            run_id: The ID of the current run.305            parent_run_id: The ID of the parent run.306            tags: The tags.307            metadata: The metadata.308            **kwargs: Additional keyword arguments.309        """310311    def on_chat_model_start(312        self,313        serialized: dict[str, Any],314        messages: list[list[BaseMessage]],315        *,316        run_id: UUID,317        parent_run_id: UUID | None = None,318        tags: list[str] | None = None,319        metadata: dict[str, Any] | None = None,320        **kwargs: Any,321    ) -> Any:322        """Run when a chat model starts running.323324        !!! warning325326            This method is called for chat models. If you're implementing a handler for327            a non-chat model, you should use `on_llm_start` instead.328329        !!! note330331            When overriding this method, the signature **must** include the two332            required positional arguments `serialized` and `messages`.  Avoid333            using `*args` in your override  doing so causes an `IndexError`334            in the fallback path when the callback system converts `messages`335            to prompt strings for `on_llm_start`.  Always declare the336            signature explicitly:337338            .. code-block:: python339340                def on_chat_model_start(341                    self,342                    serialized: dict[str, Any],343                    messages: list[list[BaseMessage]],344                    **kwargs: Any,345                ) -> None:346                    raise NotImplementedError  # triggers fallback to on_llm_start347348        Args:349            serialized: The serialized chat model.350            messages: The messages. Must be a list of message lists  this is a351                required positional argument and must be present in any override.352            run_id: The ID of the current run.353            parent_run_id: The ID of the parent run.354            tags: The tags.355            metadata: The metadata.356            **kwargs: Additional keyword arguments.357        """358        # NotImplementedError is thrown intentionally359        # Callback handler will fall back to on_llm_start if this exception is thrown360        msg = f"{self.__class__.__name__} does not implement `on_chat_model_start`"361        raise NotImplementedError(msg)362363    def on_retriever_start(364        self,365        serialized: dict[str, Any],366        query: str,367        *,368        run_id: UUID,369        parent_run_id: UUID | None = None,370        tags: list[str] | None = None,371        metadata: dict[str, Any] | None = None,372        **kwargs: Any,373    ) -> Any:374        """Run when the `Retriever` starts running.375376        Args:377            serialized: The serialized `Retriever`.378            query: The query.379            run_id: The ID of the current run.380            parent_run_id: The ID of the parent run.381            tags: The tags.382            metadata: The metadata.383            **kwargs: Additional keyword arguments.384        """385386    def on_chain_start(387        self,388        serialized: dict[str, Any],389        inputs: dict[str, Any],390        *,391        run_id: UUID,392        parent_run_id: UUID | None = None,393        tags: list[str] | None = None,394        metadata: dict[str, Any] | None = None,395        **kwargs: Any,396    ) -> Any:397        """Run when a chain starts running.398399        Args:400            serialized: The serialized chain.401            inputs: The inputs.402            run_id: The ID of the current run.403            parent_run_id: The ID of the parent run.404            tags: The tags.405            metadata: The metadata.406            **kwargs: Additional keyword arguments.407        """408409    def on_tool_start(410        self,411        serialized: dict[str, Any],412        input_str: str,413        *,414        run_id: UUID,415        parent_run_id: UUID | None = None,416        tags: list[str] | None = None,417        metadata: dict[str, Any] | None = None,418        inputs: dict[str, Any] | None = None,419        **kwargs: Any,420    ) -> Any:421        """Run when the tool starts running.422423        Args:424            serialized: The serialized chain.425            input_str: The input string.426            run_id: The ID of the current run.427            parent_run_id: The ID of the parent run.428            tags: The tags.429            metadata: The metadata.430            inputs: The inputs.431            **kwargs: Additional keyword arguments.432        """433434435class RunManagerMixin:436    """Mixin for run manager."""437438    def on_text(439        self,440        text: str,441        *,442        run_id: UUID,443        parent_run_id: UUID | None = None,444        **kwargs: Any,445    ) -> Any:446        """Run on an arbitrary text.447448        Args:449            text: The text.450            run_id: The ID of the current run.451            parent_run_id: The ID of the parent run.452            **kwargs: Additional keyword arguments.453        """454455    def on_retry(456        self,457        retry_state: RetryCallState,458        *,459        run_id: UUID,460        parent_run_id: UUID | None = None,461        **kwargs: Any,462    ) -> Any:463        """Run on a retry event.464465        Args:466            retry_state: The retry state.467            run_id: The ID of the current run.468            parent_run_id: The ID of the parent run.469            **kwargs: Additional keyword arguments.470        """471472    def on_custom_event(473        self,474        name: str,475        data: Any,476        *,477        run_id: UUID,478        tags: list[str] | None = None,479        metadata: dict[str, Any] | None = None,480        **kwargs: Any,481    ) -> Any:482        """Override to define a handler for a custom event.483484        Args:485            name: The name of the custom event.486            data: The data for the custom event.487488                Format will match the format specified by the user.489            run_id: The ID of the run.490            tags: The tags associated with the custom event (includes inherited tags).491            metadata: The metadata associated with the custom event (includes inherited492                metadata).493        """494495496class BaseCallbackHandler(497    LLMManagerMixin,498    ChainManagerMixin,499    ToolManagerMixin,500    RetrieverManagerMixin,501    CallbackManagerMixin,502    RunManagerMixin,503):504    """Base callback handler."""505506    raise_error: bool = False507    """Whether to raise an error if an exception occurs."""508509    run_inline: bool = False510    """Whether to run the callback inline."""511512    @property513    def ignore_llm(self) -> bool:514        """Whether to ignore LLM callbacks."""515        return False516517    @property518    def ignore_retry(self) -> bool:519        """Whether to ignore retry callbacks."""520        return False521522    @property523    def ignore_chain(self) -> bool:524        """Whether to ignore chain callbacks."""525        return False526527    @property528    def ignore_agent(self) -> bool:529        """Whether to ignore agent callbacks."""530        return False531532    @property533    def ignore_retriever(self) -> bool:534        """Whether to ignore retriever callbacks."""535        return False536537    @property538    def ignore_chat_model(self) -> bool:539        """Whether to ignore chat model callbacks."""540        return False541542    @property543    def ignore_custom_event(self) -> bool:544        """Ignore custom event."""545        return False546547548class AsyncCallbackHandler(BaseCallbackHandler):549    """Base async callback handler."""550551    async def on_llm_start(552        self,553        serialized: dict[str, Any],554        prompts: list[str],555        *,556        run_id: UUID,557        parent_run_id: UUID | None = None,558        tags: list[str] | None = None,559        metadata: dict[str, Any] | None = None,560        **kwargs: Any,561    ) -> None:562        """Run when the model starts running.563564        !!! warning565566            This method is called for non-chat models (regular text completion LLMs). If567            you're implementing a handler for a chat model, you should use568            `on_chat_model_start` instead.569570        Args:571            serialized: The serialized LLM.572            prompts: The prompts.573            run_id: The ID of the current run.574            parent_run_id: The ID of the parent run.575            tags: The tags.576            metadata: The metadata.577            **kwargs: Additional keyword arguments.578        """579580    async def on_chat_model_start(581        self,582        serialized: dict[str, Any],583        messages: list[list[BaseMessage]],584        *,585        run_id: UUID,586        parent_run_id: UUID | None = None,587        tags: list[str] | None = None,588        metadata: dict[str, Any] | None = None,589        **kwargs: Any,590    ) -> Any:591        """Run when a chat model starts running.592593        !!! warning594595            This method is called for chat models. If you're implementing a handler for596            a non-chat model, you should use `on_llm_start` instead.597598        !!! note599600            When overriding this method, the signature **must** include the two601            required positional arguments `serialized` and `messages`.  Avoid602            using `*args` in your override  doing so causes an `IndexError`603            in the fallback path when the callback system converts `messages`604            to prompt strings for `on_llm_start`.  Always declare the605            signature explicitly:606607            .. code-block:: python608609                async def on_chat_model_start(610                    self,611                    serialized: dict[str, Any],612                    messages: list[list[BaseMessage]],613                    **kwargs: Any,614                ) -> None:615                    raise NotImplementedError  # triggers fallback to on_llm_start616617        Args:618            serialized: The serialized chat model.619            messages: The messages. Must be a list of message lists  this is a620                required positional argument and must be present in any override.621            run_id: The ID of the current run.622            parent_run_id: The ID of the parent run.623            tags: The tags.624            metadata: The metadata.625            **kwargs: Additional keyword arguments.626        """627        # NotImplementedError is thrown intentionally628        # Callback handler will fall back to on_llm_start if this exception is thrown629        msg = f"{self.__class__.__name__} does not implement `on_chat_model_start`"630        raise NotImplementedError(msg)631632    async def on_llm_new_token(633        self,634        token: str,635        *,636        chunk: GenerationChunk | ChatGenerationChunk | None = None,637        run_id: UUID,638        parent_run_id: UUID | None = None,639        tags: list[str] | None = None,640        **kwargs: Any,641    ) -> None:642        """Run on new output token. Only available when streaming is enabled.643644        For both chat models and non-chat models (legacy text completion LLMs).645646        Args:647            token: The new token.648            chunk: The new generated chunk, containing content and other information.649            run_id: The ID of the current run.650            parent_run_id: The ID of the parent run.651            tags: The tags.652            **kwargs: Additional keyword arguments.653        """654655    async def on_llm_end(656        self,657        response: LLMResult,658        *,659        run_id: UUID,660        parent_run_id: UUID | None = None,661        tags: list[str] | None = None,662        **kwargs: Any,663    ) -> None:664        """Run when the model ends running.665666        Args:667            response: The response which was generated.668            run_id: The ID of the current run.669            parent_run_id: The ID of the parent run.670            tags: The tags.671            **kwargs: Additional keyword arguments.672        """673674    async def on_llm_error(675        self,676        error: BaseException,677        *,678        run_id: UUID,679        parent_run_id: UUID | None = None,680        tags: list[str] | None = None,681        **kwargs: Any,682    ) -> None:683        """Run when LLM errors.684685        Args:686            error: The error that occurred.687            run_id: The ID of the current run.688            parent_run_id: The ID of the parent run.689            tags: The tags.690            **kwargs: Additional keyword arguments.691692                - response (LLMResult): The response which was generated before693                    the error occurred.694        """695696    async def on_stream_event(697        self,698        event: MessagesData,699        *,700        run_id: UUID,701        parent_run_id: UUID | None = None,702        tags: list[str] | None = None,703        **kwargs: Any,704    ) -> None:705        """Run on each protocol event produced by `astream_events(version="v3")`.706707        See :meth:`LLMManagerMixin.on_stream_event` for the full contract.708        Fires once per `MessagesData` event at event granularity, uniformly709        across native and compat-bridge providers, and is purely additive710        to the existing `on_chat_model_start` / `on_llm_end` /711        `on_llm_error` callbacks.712713        Args:714            event: The protocol event.715            run_id: The ID of the current run.716            parent_run_id: The ID of the parent run.717            tags: The tags.718            **kwargs: Additional keyword arguments.719        """720721    async def on_chain_start(722        self,723        serialized: dict[str, Any],724        inputs: dict[str, Any],725        *,726        run_id: UUID,727        parent_run_id: UUID | None = None,728        tags: list[str] | None = None,729        metadata: dict[str, Any] | None = None,730        **kwargs: Any,731    ) -> None:732        """Run when a chain starts running.733734        Args:735            serialized: The serialized chain.736            inputs: The inputs.737            run_id: The ID of the current run.738            parent_run_id: The ID of the parent run.739            tags: The tags.740            metadata: The metadata.741            **kwargs: Additional keyword arguments.742        """743744    async def on_chain_end(745        self,746        outputs: dict[str, Any],747        *,748        run_id: UUID,749        parent_run_id: UUID | None = None,750        tags: list[str] | None = None,751        **kwargs: Any,752    ) -> None:753        """Run when a chain ends running.754755        Args:756            outputs: The outputs of the chain.757            run_id: The ID of the current run.758            parent_run_id: The ID of the parent run.759            tags: The tags.760            **kwargs: Additional keyword arguments.761        """762763    async def on_chain_error(764        self,765        error: BaseException,766        *,767        run_id: UUID,768        parent_run_id: UUID | None = None,769        tags: list[str] | None = None,770        **kwargs: Any,771    ) -> None:772        """Run when chain errors.773774        Args:775            error: The error that occurred.776            run_id: The ID of the current run.777            parent_run_id: The ID of the parent run.778            tags: The tags.779            **kwargs: Additional keyword arguments.780        """781782    async def on_tool_start(783        self,784        serialized: dict[str, Any],785        input_str: str,786        *,787        run_id: UUID,788        parent_run_id: UUID | None = None,789        tags: list[str] | None = None,790        metadata: dict[str, Any] | None = None,791        inputs: dict[str, Any] | None = None,792        **kwargs: Any,793    ) -> None:794        """Run when the tool starts running.795796        Args:797            serialized: The serialized tool.798            input_str: The input string.799            run_id: The ID of the current run.800            parent_run_id: The ID of the parent run.801            tags: The tags.802            metadata: The metadata.803            inputs: The inputs.804            **kwargs: Additional keyword arguments.805        """806807    async def on_tool_end(808        self,809        output: Any,810        *,811        run_id: UUID,812        parent_run_id: UUID | None = None,813        tags: list[str] | None = None,814        **kwargs: Any,815    ) -> None:816        """Run when the tool ends running.817818        Args:819            output: The output of the tool.820            run_id: The ID of the current run.821            parent_run_id: The ID of the parent run.822            tags: The tags.823            **kwargs: Additional keyword arguments.824        """825826    async def on_tool_error(827        self,828        error: BaseException,829        *,830        run_id: UUID,831        parent_run_id: UUID | None = None,832        tags: list[str] | None = None,833        **kwargs: Any,834    ) -> None:835        """Run when tool errors.836837        Args:838            error: The error that occurred.839            run_id: The ID of the current run.840            parent_run_id: The ID of the parent run.841            tags: The tags.842            **kwargs: Additional keyword arguments.843        """844845    async def on_text(846        self,847        text: str,848        *,849        run_id: UUID,850        parent_run_id: UUID | None = None,851        tags: list[str] | None = None,852        **kwargs: Any,853    ) -> None:854        """Run on an arbitrary text.855856        Args:857            text: The text.858            run_id: The ID of the current run.859            parent_run_id: The ID of the parent run.860            tags: The tags.861            **kwargs: Additional keyword arguments.862        """863864    async def on_retry(865        self,866        retry_state: RetryCallState,867        *,868        run_id: UUID,869        parent_run_id: UUID | None = None,870        **kwargs: Any,871    ) -> Any:872        """Run on a retry event.873874        Args:875            retry_state: The retry state.876            run_id: The ID of the current run.877            parent_run_id: The ID of the parent run.878            **kwargs: Additional keyword arguments.879        """880881    async def on_agent_action(882        self,883        action: AgentAction,884        *,885        run_id: UUID,886        parent_run_id: UUID | None = None,887        tags: list[str] | None = None,888        **kwargs: Any,889    ) -> None:890        """Run on agent action.891892        Args:893            action: The agent action.894            run_id: The ID of the current run.895            parent_run_id: The ID of the parent run.896            tags: The tags.897            **kwargs: Additional keyword arguments.898        """899900    async def on_agent_finish(901        self,902        finish: AgentFinish,903        *,904        run_id: UUID,905        parent_run_id: UUID | None = None,906        tags: list[str] | None = None,907        **kwargs: Any,908    ) -> None:909        """Run on the agent end.910911        Args:912            finish: The agent finish.913            run_id: The ID of the current run.914            parent_run_id: The ID of the parent run.915            tags: The tags.916            **kwargs: Additional keyword arguments.917        """918919    async def on_retriever_start(920        self,921        serialized: dict[str, Any],922        query: str,923        *,924        run_id: UUID,925        parent_run_id: UUID | None = None,926        tags: list[str] | None = None,927        metadata: dict[str, Any] | None = None,928        **kwargs: Any,929    ) -> None:930        """Run on the retriever start.931932        Args:933            serialized: The serialized retriever.934            query: The query.935            run_id: The ID of the current run.936            parent_run_id: The ID of the parent run.937            tags: The tags.938            metadata: The metadata.939            **kwargs: Additional keyword arguments.940        """941942    async def on_retriever_end(943        self,944        documents: Sequence[Document],945        *,946        run_id: UUID,947        parent_run_id: UUID | None = None,948        tags: list[str] | None = None,949        **kwargs: Any,950    ) -> None:951        """Run on the retriever end.952953        Args:954            documents: The documents retrieved.955            run_id: The ID of the current run.956            parent_run_id: The ID of the parent run.957            tags: The tags.958            **kwargs: Additional keyword arguments.959        """960961    async def on_retriever_error(962        self,963        error: BaseException,964        *,965        run_id: UUID,966        parent_run_id: UUID | None = None,967        tags: list[str] | None = None,968        **kwargs: Any,969    ) -> None:970        """Run on retriever error.971972        Args:973            error: The error that occurred.974            run_id: The ID of the current run.975            parent_run_id: The ID of the parent run.976            tags: The tags.977            **kwargs: Additional keyword arguments.978        """979980    async def on_custom_event(981        self,982        name: str,983        data: Any,984        *,985        run_id: UUID,986        tags: list[str] | None = None,987        metadata: dict[str, Any] | None = None,988        **kwargs: Any,989    ) -> None:990        """Override to define a handler for custom events.991992        Args:993            name: The name of the custom event.994            data: The data for the custom event.995996                Format will match the format specified by the user.997            run_id: The ID of the run.998            tags: The tags associated with the custom event (includes inherited tags).999            metadata: The metadata associated with the custom event (includes inherited1000                metadata).1001        """100210031004class BaseCallbackManager(CallbackManagerMixin):1005    """Base callback manager."""10061007    def __init__(1008        self,1009        handlers: list[BaseCallbackHandler],1010        inheritable_handlers: list[BaseCallbackHandler] | None = None,1011        parent_run_id: UUID | None = None,1012        *,1013        tags: list[str] | None = None,1014        inheritable_tags: list[str] | None = None,1015        metadata: dict[str, Any] | None = None,1016        inheritable_metadata: dict[str, Any] | None = None,1017    ) -> None:1018        """Initialize callback manager.10191020        Args:1021            handlers: The handlers.1022            inheritable_handlers: The inheritable handlers.1023            parent_run_id: The parent run ID.1024            tags: The tags.1025            inheritable_tags: The inheritable tags.1026            metadata: The metadata.1027            inheritable_metadata: The inheritable metadata.1028        """1029        self.handlers: list[BaseCallbackHandler] = handlers1030        self.inheritable_handlers: list[BaseCallbackHandler] = (1031            inheritable_handlers or []1032        )1033        self.parent_run_id: UUID | None = parent_run_id1034        self.tags = tags or []1035        self.inheritable_tags = inheritable_tags or []1036        self.metadata = metadata or {}1037        self.inheritable_metadata = inheritable_metadata or {}10381039    def copy(self) -> Self:1040        """Return a copy of the callback manager."""1041        return self.__class__(1042            handlers=self.handlers.copy(),1043            inheritable_handlers=self.inheritable_handlers.copy(),1044            parent_run_id=self.parent_run_id,1045            tags=self.tags.copy(),1046            inheritable_tags=self.inheritable_tags.copy(),1047            metadata=self.metadata.copy(),1048            inheritable_metadata=self.inheritable_metadata.copy(),1049        )10501051    def merge(self, other: BaseCallbackManager) -> Self:1052        """Merge the callback manager with another callback manager.10531054        May be overwritten in subclasses.10551056        Primarily used internally within `merge_configs`.10571058        Returns:1059            The merged callback manager of the same type as the current object.10601061        Example:1062            ```python1063            # Merging two callback managers`1064            from langchain_core.callbacks.manager import (1065                CallbackManager,1066                trace_as_chain_group,1067            )1068            from langchain_core.callbacks.stdout import StdOutCallbackHandler10691070            manager = CallbackManager(handlers=[StdOutCallbackHandler()], tags=["tag2"])1071            with trace_as_chain_group("My Group Name", tags=["tag1"]) as group_manager:1072                merged_manager = group_manager.merge(manager)1073                print(merged_manager.handlers)1074                # [1075                #    <langchain_core.callbacks.stdout.StdOutCallbackHandler object at ...>,1076                #    <langchain_core.callbacks.streaming_stdout.StreamingStdOutCallbackHandler object at ...>,1077                # ]10781079                print(merged_manager.tags)1080                #    ['tag2', 'tag1']1081            ```1082        """  # noqa: E5011083        # Combine handlers and inheritable_handlers separately, using sets1084        # to deduplicate (order not preserved)1085        combined_handlers = list(set(self.handlers) | set(other.handlers))1086        combined_inheritable = list(1087            set(self.inheritable_handlers) | set(other.inheritable_handlers)1088        )10891090        return self.__class__(1091            parent_run_id=self.parent_run_id or other.parent_run_id,1092            handlers=combined_handlers,1093            inheritable_handlers=combined_inheritable,1094            tags=list(set(self.tags + other.tags)),1095            inheritable_tags=list(set(self.inheritable_tags + other.inheritable_tags)),1096            metadata={1097                **self.metadata,1098                **other.metadata,1099            },1100            inheritable_metadata={1101                **self.inheritable_metadata,1102                **other.inheritable_metadata,1103            },1104        )11051106    @property1107    def is_async(self) -> bool:1108        """Whether the callback manager is async."""1109        return False11101111    def add_handler(1112        self,1113        handler: BaseCallbackHandler,1114        inherit: bool = True,  # noqa: FBT001,FBT0021115    ) -> None:1116        """Add a handler to the callback manager.11171118        Args:1119            handler: The handler to add.1120            inherit: Whether to inherit the handler.1121        """1122        if handler not in self.handlers:1123            self.handlers.append(handler)1124        if inherit and handler not in self.inheritable_handlers:1125            self.inheritable_handlers.append(handler)11261127    def remove_handler(self, handler: BaseCallbackHandler) -> None:1128        """Remove a handler from the callback manager.11291130        Args:1131            handler: The handler to remove.1132        """1133        if handler in self.handlers:1134            self.handlers.remove(handler)1135        if handler in self.inheritable_handlers:1136            self.inheritable_handlers.remove(handler)11371138    def set_handlers(1139        self,1140        handlers: list[BaseCallbackHandler],1141        inherit: bool = True,  # noqa: FBT001,FBT0021142    ) -> None:1143        """Set handlers as the only handlers on the callback manager.11441145        Args:1146            handlers: The handlers to set.1147            inherit: Whether to inherit the handlers.1148        """1149        self.handlers = []1150        self.inheritable_handlers = []1151        for handler in handlers:1152            self.add_handler(handler, inherit=inherit)11531154    def set_handler(1155        self,1156        handler: BaseCallbackHandler,1157        inherit: bool = True,  # noqa: FBT001,FBT0021158    ) -> None:1159        """Set handler as the only handler on the callback manager.11601161        Args:1162            handler: The handler to set.1163            inherit: Whether to inherit the handler.1164        """1165        self.set_handlers([handler], inherit=inherit)11661167    def add_tags(1168        self,1169        tags: list[str],1170        inherit: bool = True,  # noqa: FBT001,FBT0021171    ) -> None:1172        """Add tags to the callback manager.11731174        Args:1175            tags: The tags to add.1176            inherit: Whether to inherit the tags.1177        """1178        for tag in tags:1179            if tag in self.tags:1180                self.remove_tags([tag])1181        self.tags.extend(tags)1182        if inherit:1183            self.inheritable_tags.extend(tags)11841185    def remove_tags(self, tags: list[str]) -> None:1186        """Remove tags from the callback manager.11871188        Args:1189            tags: The tags to remove.1190        """1191        for tag in tags:1192            if tag in self.tags:1193                self.tags.remove(tag)1194            if tag in self.inheritable_tags:1195                self.inheritable_tags.remove(tag)11961197    def add_metadata(1198        self,1199        metadata: dict[str, Any],1200        inherit: bool = True,  # noqa: FBT001,FBT0021201    ) -> None:1202        """Add metadata to the callback manager.12031204        Args:1205            metadata: The metadata to add.1206            inherit: Whether to inherit the metadata.1207        """1208        self.metadata.update(metadata)1209        if inherit:1210            self.inheritable_metadata.update(metadata)12111212    def remove_metadata(self, keys: list[str]) -> None:1213        """Remove metadata from the callback manager.12141215        Args:1216            keys: The keys to remove.1217        """1218        for key in keys:1219            self.metadata.pop(key, None)1220            self.inheritable_metadata.pop(key, None)122112221223Callbacks = list[BaseCallbackHandler] | BaseCallbackManager | None

Code quality findings 51

Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_end(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_new_token(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_end(
Ensure functions have docstrings for documentation
missing-docstring
def on_llm_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_stream_event(
Ensure functions have docstrings for documentation
missing-docstring
def on_chain_end(
Ensure functions have docstrings for documentation
missing-docstring
def on_chain_error(
Ensure functions have docstrings for documentation
missing-docstring
def on_agent_action(
Ensure functions have docstrings for documentation
missing-docstring
def on_agent_finish(
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
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_chat_model_start(
Ensure functions have docstrings for documentation
missing-docstring
def on_retriever_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_text(
Ensure functions have docstrings for documentation
missing-docstring
def on_retry(
Ensure functions have docstrings for documentation
missing-docstring
def on_custom_event(
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_chat_model_start(
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_end(
Ensure functions have docstrings for documentation
missing-docstring
async def on_llm_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_stream_event(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_end(
Ensure functions have docstrings for documentation
missing-docstring
async def on_chain_error(
Ensure functions have docstrings for documentation
missing-docstring
async def on_tool_start(
Ensure functions have docstrings for documentation
missing-docstring
async def on_tool_end(
Ensure functions have docstrings for documentation
missing-docstring
async def on_tool_error(
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
async def on_agent_action(
Ensure functions have docstrings for documentation
missing-docstring
async def on_agent_finish(
Ensure functions have docstrings for documentation
missing-docstring
async def on_retriever_start(
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
async def on_custom_event(
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)
Avoid unnecessary list conversions; use generators where possible
unnecessary-list
combined_handlers = list(set(self.handlers) | set(other.handlers))
Avoid unnecessary list conversions; use generators where possible
unnecessary-list
combined_inheritable = list(
Ensure functions have docstrings for documentation
missing-docstring
def add_handler(
Ensure functions have docstrings for documentation
missing-docstring
def set_handlers(
Ensure functions have docstrings for documentation
missing-docstring
def set_handler(
Ensure functions have docstrings for documentation
missing-docstring
def add_tags(
Ensure functions have docstrings for documentation
missing-docstring
def add_metadata(

Get this view in your editor

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