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