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