libs/core/langchain_core/runnables/base.py PYTHON 6,726 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 6,726.
1"""Base classes and utilities for `Runnable` objects."""23from __future__ import annotations45import asyncio6import collections7import contextlib8import functools9import inspect10import threading11from abc import ABC, abstractmethod12from collections.abc import (13    AsyncGenerator,14    AsyncIterator,15    Awaitable,16    Callable,17    Coroutine,18    Iterator,19    Mapping,20    Sequence,21)22from concurrent.futures import FIRST_COMPLETED, wait23from functools import wraps24from itertools import tee25from operator import itemgetter26from types import GenericAlias27from typing import (28    TYPE_CHECKING,29    Any,30    Generic,31    Literal,32    Protocol,33    TypeVar,34    cast,35    get_args,36    get_type_hints,37    overload,38)3940from pydantic import BaseModel, ConfigDict, Field, RootModel41from pydantic.fields import FieldInfo42from typing_extensions import override4344from langchain_core._api import beta_decorator45from langchain_core._api.deprecation import warn_deprecated46from langchain_core.callbacks.manager import AsyncCallbackManager, CallbackManager47from langchain_core.load.serializable import (48    Serializable,49    SerializedConstructor,50    SerializedNotImplemented,51)52from langchain_core.runnables.config import (53    RunnableConfig,54    acall_func_with_variable_args,55    call_func_with_variable_args,56    ensure_config,57    get_async_callback_manager_for_config,58    get_callback_manager_for_config,59    get_config_list,60    get_executor_for_config,61    merge_configs,62    patch_config,63    run_in_executor,64    set_config_context,65)66from langchain_core.runnables.utils import (67    AddableDict,68    AnyConfigurableField,69    ConfigurableField,70    ConfigurableFieldSpec,71    Input,72    Output,73    accepts_config,74    accepts_run_manager,75    coro_with_context,76    gated_coro,77    gather_with_concurrency,78    get_function_first_arg_dict_keys,79    get_function_nonlocals,80    get_lambda_source,81    get_unique_config_specs,82    indent_lines_after_first,83    is_async_callable,84    is_async_generator,85)86from langchain_core.tracers._streaming import _StreamingCallbackHandler87from langchain_core.tracers.event_stream import (88    _astream_events_implementation_v1,89    _astream_events_implementation_v2,90)91from langchain_core.tracers.log_stream import (92    LogStreamCallbackHandler,93    _astream_log_implementation,94)95from langchain_core.tracers.root_listeners import (96    AsyncRootListenersTracer,97    RootListenersTracer,98)99from langchain_core.utils.aiter import aclosing, atee100from langchain_core.utils.iter import safetee101from langchain_core.utils.pydantic import (102    TypeBaseModel,103    create_model_v2,104    get_fields,105    model_json_schema,106)107108if TYPE_CHECKING:109    from pydantic.v1.fields import ModelField110111    from langchain_core.callbacks.manager import (112        AsyncCallbackManagerForChainRun,113        CallbackManagerForChainRun,114    )115    from langchain_core.prompts.base import BasePromptTemplate116    from langchain_core.runnables.fallbacks import (117        RunnableWithFallbacks as RunnableWithFallbacksT,118    )119    from langchain_core.runnables.graph import Graph120    from langchain_core.runnables.retry import ExponentialJitterParams121    from langchain_core.runnables.schema import StreamEvent122    from langchain_core.tools import BaseTool123    from langchain_core.tracers.log_stream import RunLog, RunLogPatch124    from langchain_core.tracers.root_listeners import AsyncListener125    from langchain_core.tracers.schemas import Run126127128Other = TypeVar("Other")129130_RUNNABLE_GENERIC_NUM_ARGS = 2  # Input and Output131132133class Runnable(ABC, Generic[Input, Output]):134    """A unit of work that can be invoked, batched, streamed, transformed and composed.135136    Key Methods137    ===========138139    - `invoke`/`ainvoke`: Transforms a single input into an output.140    - `batch`/`abatch`: Efficiently transforms multiple inputs into outputs.141    - `stream`/`astream`: Streams output from a single input as it's produced.142    - `astream_log`: Streams output and selected intermediate results from an143        input.144145    Built-in optimizations:146147    - **Batch**: By default, batch runs invoke() in parallel using a thread pool148        executor. Override to optimize batching.149150    - **Async**: Methods with `'a'` prefix are asynchronous. By default, they execute151        the sync counterpart using asyncio's thread pool.152        Override for native async.153154    All methods accept an optional config argument, which can be used to configure155    execution, add tags and metadata for tracing and debugging etc.156157    Runnables expose schematic information about their input, output and config via158    the `input_schema` property, the `output_schema` property and `config_schema`159    method.160161    Composition162    ===========163164    Runnable objects can be composed together to create chains in a declarative way.165166    Any chain constructed this way will automatically have sync, async, batch, and167    streaming support.168169    The main composition primitives are `RunnableSequence` and `RunnableParallel`.170171    **`RunnableSequence`** invokes a series of runnables sequentially, with172    one Runnable's output serving as the next's input. Construct using173    the `|` operator or by passing a list of runnables to `RunnableSequence`.174175    **`RunnableParallel`** invokes runnables concurrently, providing the same input176    to each. Construct it using a dict literal within a sequence or by passing a177    dict to `RunnableParallel`.178179180    For example,181182    ```python183    from langchain_core.runnables import RunnableLambda184185    # A RunnableSequence constructed using the `|` operator186    sequence = RunnableLambda(lambda x: x + 1) | RunnableLambda(lambda x: x * 2)187    sequence.invoke(1)  # 4188    sequence.batch([1, 2, 3])  # [4, 6, 8]189190191    # A sequence that contains a RunnableParallel constructed using a dict literal192    sequence = RunnableLambda(lambda x: x + 1) | {193        "mul_2": RunnableLambda(lambda x: x * 2),194        "mul_5": RunnableLambda(lambda x: x * 5),195    }196    sequence.invoke(1)  # {'mul_2': 4, 'mul_5': 10}197    ```198199    Standard Methods200    ================201202    All `Runnable`s expose additional methods that can be used to modify their203    behavior (e.g., add a retry policy, add lifecycle listeners, make them204    configurable, etc.).205206    These methods will work on any `Runnable`, including `Runnable` chains207    constructed by composing other `Runnable`s.208    See the individual methods for details.209210    For example,211212    ```python213    from langchain_core.runnables import RunnableLambda214215    import random216217    def add_one(x: int) -> int:218        return x + 1219220221    def buggy_double(y: int) -> int:222        \"\"\"Buggy code that will fail 70% of the time\"\"\"223        if random.random() > 0.3:224            print('This code failed, and will probably be retried!')  # noqa: T201225            raise ValueError('Triggered buggy code')226        return y * 2227228    sequence = (229        RunnableLambda(add_one) |230        RunnableLambda(buggy_double).with_retry( # Retry on failure231            stop_after_attempt=10,232            wait_exponential_jitter=False233        )234    )235236    print(sequence.input_schema.model_json_schema()) # Show inferred input schema237    print(sequence.output_schema.model_json_schema()) # Show inferred output schema238    print(sequence.invoke(2)) # invoke the sequence (note the retry above!!)239    ```240241    Debugging and tracing242    =====================243244    As the chains get longer, it can be useful to be able to see intermediate results245    to debug and trace the chain.246247    You can set the global debug flag to True to enable debug output for all chains:248249    ```python250    from langchain_core.globals import set_debug251252    set_debug(True)253    ```254255    Alternatively, you can pass existing or custom callbacks to any given chain:256257    ```python258    from langchain_core.tracers import ConsoleCallbackHandler259260    chain.invoke(..., config={"callbacks": [ConsoleCallbackHandler()]})261    ```262263    For a UI (and much more) checkout [LangSmith](https://docs.langchain.com/langsmith/home).264265    """266267    name: str | None268    """The name of the `Runnable`. Used for debugging and tracing."""269270    def get_name(self, suffix: str | None = None, *, name: str | None = None) -> str:271        """Get the name of the `Runnable`.272273        Args:274            suffix: An optional suffix to append to the name.275            name: An optional name to use instead of the `Runnable`'s name.276277        Returns:278            The name of the `Runnable`.279        """280        if name:281            name_ = name282        elif hasattr(self, "name") and self.name:283            name_ = self.name284        else:285            # Here we handle a case where the runnable subclass is also a pydantic286            # model.287            cls = self.__class__288            # Then it's a pydantic sub-class, and we have to check289            # whether it's a generic, and if so recover the original name.290            if (291                hasattr(292                    cls,293                    "__pydantic_generic_metadata__",294                )295                and "origin" in cls.__pydantic_generic_metadata__296                and cls.__pydantic_generic_metadata__["origin"] is not None297            ):298                name_ = cls.__pydantic_generic_metadata__["origin"].__name__299            else:300                name_ = cls.__name__301302        if suffix:303            if name_[0].isupper():304                return name_ + suffix.title()305            return name_ + "_" + suffix.lower()306        return name_307308    @property309    def InputType(self) -> type[Input]:  # noqa: N802310        """Input type.311312        The type of input this `Runnable` accepts specified as a type annotation.313314        Raises:315            TypeError: If the input type cannot be inferred.316        """317        # First loop through all parent classes and if any of them is318        # a Pydantic model, we will pick up the generic parameterization319        # from that model via the __pydantic_generic_metadata__ attribute.320        for base in self.__class__.mro():321            if hasattr(base, "__pydantic_generic_metadata__"):322                metadata = base.__pydantic_generic_metadata__323                if (324                    "args" in metadata325                    and len(metadata["args"]) == _RUNNABLE_GENERIC_NUM_ARGS326                ):327                    return cast("type[Input]", metadata["args"][0])328329        # If we didn't find a Pydantic model in the parent classes,330        # then loop through __orig_bases__. This corresponds to331        # Runnables that are not pydantic models.332        for cls in self.__class__.__orig_bases__:  # type: ignore[attr-defined]333            type_args = get_args(cls)334            if type_args and len(type_args) == _RUNNABLE_GENERIC_NUM_ARGS:335                return cast("type[Input]", type_args[0])336337        msg = (338            f"Runnable {self.get_name()} doesn't have an inferable InputType. "339            "Override the InputType property to specify the input type."340        )341        raise TypeError(msg)342343    @property344    def OutputType(self) -> type[Output]:  # noqa: N802345        """Output Type.346347        The type of output this `Runnable` produces specified as a type annotation.348349        Raises:350            TypeError: If the output type cannot be inferred.351        """352        # First loop through bases -- this will help generic353        # any pydantic models.354        for base in self.__class__.mro():355            if hasattr(base, "__pydantic_generic_metadata__"):356                metadata = base.__pydantic_generic_metadata__357                if (358                    "args" in metadata359                    and len(metadata["args"]) == _RUNNABLE_GENERIC_NUM_ARGS360                ):361                    return cast("type[Output]", metadata["args"][1])362363        for cls in self.__class__.__orig_bases__:  # type: ignore[attr-defined]364            type_args = get_args(cls)365            if type_args and len(type_args) == _RUNNABLE_GENERIC_NUM_ARGS:366                return cast("type[Output]", type_args[1])367368        msg = (369            f"Runnable {self.get_name()} doesn't have an inferable OutputType. "370            "Override the OutputType property to specify the output type."371        )372        raise TypeError(msg)373374    @property375    def input_schema(self) -> TypeBaseModel:376        """The type of input this `Runnable` accepts specified as a Pydantic model."""377        return self.get_input_schema()378379    def get_input_schema(380        self,381        config: RunnableConfig | None = None,382    ) -> TypeBaseModel:383        """Get a Pydantic model that can be used to validate input to the `Runnable`.384385        `Runnable` objects that leverage the `configurable_fields` and386        `configurable_alternatives` methods will have a dynamic input schema that387        depends on which configuration the `Runnable` is invoked with.388389        This method allows to get an input schema for a specific configuration.390391        Args:392            config: A config to use when generating the schema.393394        Returns:395            A Pydantic model that can be used to validate input.396        """397        _ = config398        root_type = self.InputType399400        if (401            inspect.isclass(root_type)402            and not isinstance(root_type, GenericAlias)403            and issubclass(root_type, BaseModel)404        ):405            return root_type406407        return create_model_v2(408            self.get_name("Input"),409            root=root_type,410            # create model needs access to appropriate type annotations to be411            # able to construct the Pydantic model.412            # When we create the model, we pass information about the namespace413            # where the model is being created, so the type annotations can414            # be resolved correctly as well.415            # self.__class__.__module__ handles the case when the Runnable is416            # being sub-classed in a different module.417            module_name=self.__class__.__module__,418        )419420    def get_input_jsonschema(421        self, config: RunnableConfig | None = None422    ) -> dict[str, Any]:423        """Get a JSON schema that represents the input to the `Runnable`.424425        Args:426            config: A config to use when generating the schema.427428        Returns:429            A JSON schema that represents the input to the `Runnable`.430431        Example:432            ```python433            from langchain_core.runnables import RunnableLambda434435436            def add_one(x: int) -> int:437                return x + 1438439440            runnable = RunnableLambda(add_one)441442            print(runnable.get_input_jsonschema())443            ```444445        !!! version-added "Added in `langchain-core` 0.3.0"446447        """448        return model_json_schema(self.get_input_schema(config))449450    @property451    def output_schema(self) -> TypeBaseModel:452        """Output schema.453454        The type of output this `Runnable` produces specified as a Pydantic model.455        """456        return self.get_output_schema()457458    def get_output_schema(459        self,460        config: RunnableConfig | None = None,461    ) -> TypeBaseModel:462        """Get a Pydantic model that can be used to validate output to the `Runnable`.463464        `Runnable` objects that leverage the `configurable_fields` and465        `configurable_alternatives` methods will have a dynamic output schema that466        depends on which configuration the `Runnable` is invoked with.467468        This method allows to get an output schema for a specific configuration.469470        Args:471            config: A config to use when generating the schema.472473        Returns:474            A Pydantic model that can be used to validate output.475        """476        _ = config477        root_type = self.OutputType478479        if (480            inspect.isclass(root_type)481            and not isinstance(root_type, GenericAlias)482            and issubclass(root_type, BaseModel)483        ):484            return root_type485486        return create_model_v2(487            self.get_name("Output"),488            root=root_type,489            # create model needs access to appropriate type annotations to be490            # able to construct the Pydantic model.491            # When we create the model, we pass information about the namespace492            # where the model is being created, so the type annotations can493            # be resolved correctly as well.494            # self.__class__.__module__ handles the case when the Runnable is495            # being sub-classed in a different module.496            module_name=self.__class__.__module__,497        )498499    def get_output_jsonschema(500        self, config: RunnableConfig | None = None501    ) -> dict[str, Any]:502        """Get a JSON schema that represents the output of the `Runnable`.503504        Args:505            config: A config to use when generating the schema.506507        Returns:508            A JSON schema that represents the output of the `Runnable`.509510        Example:511            ```python512            from langchain_core.runnables import RunnableLambda513514515            def add_one(x: int) -> int:516                return x + 1517518519            runnable = RunnableLambda(add_one)520521            print(runnable.get_output_jsonschema())522            ```523524        !!! version-added "Added in `langchain-core` 0.3.0"525526        """527        return model_json_schema(self.get_output_schema(config))528529    @property530    def config_specs(self) -> list[ConfigurableFieldSpec]:531        """List configurable fields for this `Runnable`."""532        return []533534    def config_schema(self, *, include: Sequence[str] | None = None) -> type[BaseModel]:535        """The type of config this `Runnable` accepts specified as a Pydantic model.536537        To mark a field as configurable, see the `configurable_fields`538        and `configurable_alternatives` methods.539540        Args:541            include: A list of fields to include in the config schema.542543        Returns:544            A Pydantic model that can be used to validate config.545546        """547        include = include or []548        config_specs = self.config_specs549        configurable = (550            create_model_v2(551                "Configurable",552                field_definitions={553                    spec.id: (554                        spec.annotation,555                        Field(556                            spec.default, title=spec.name, description=spec.description557                        ),558                    )559                    for spec in config_specs560                },561            )562            if config_specs563            else None564        )565566        # Many need to create a typed dict instead to implement NotRequired!567        all_fields = {568            **({"configurable": (configurable, None)} if configurable else {}),569            **{570                field_name: (field_type, None)571                for field_name, field_type in get_type_hints(RunnableConfig).items()572                if field_name in [i for i in include if i != "configurable"]573            },574        }575        return create_model_v2(self.get_name("Config"), field_definitions=all_fields)576577    def get_config_jsonschema(578        self, *, include: Sequence[str] | None = None579    ) -> dict[str, Any]:580        """Get a JSON schema that represents the config of the `Runnable`.581582        Args:583            include: A list of fields to include in the config schema.584585        Returns:586            A JSON schema that represents the config of the `Runnable`.587588        !!! version-added "Added in `langchain-core` 0.3.0"589590        """591        return self.config_schema(include=include).model_json_schema()592593    def get_graph(self, config: RunnableConfig | None = None) -> Graph:594        """Return a graph representation of this `Runnable`."""595        # Import locally to prevent circular import596        from langchain_core.runnables.graph import Graph  # noqa: PLC0415597598        graph = Graph()599        try:600            input_node = graph.add_node(self.get_input_schema(config))601        except TypeError:602            input_node = graph.add_node(create_model_v2(self.get_name("Input")))603        runnable_node = graph.add_node(604            self, metadata=config.get("metadata") if config else None605        )606        try:607            output_node = graph.add_node(self.get_output_schema(config))608        except TypeError:609            output_node = graph.add_node(create_model_v2(self.get_name("Output")))610        graph.add_edge(input_node, runnable_node)611        graph.add_edge(runnable_node, output_node)612        return graph613614    def get_prompts(615        self, config: RunnableConfig | None = None616    ) -> list[BasePromptTemplate[Any]]:617        """Return a list of prompts used by this `Runnable`."""618        # Import locally to prevent circular import619        from langchain_core.prompts.base import BasePromptTemplate  # noqa: PLC0415620621        return [622            node.data623            for node in self.get_graph(config=config).nodes.values()624            if isinstance(node.data, BasePromptTemplate)625        ]626627    @overload628    def __or__(629        self, other: Mapping[str, Any]630    ) -> RunnableSerializable[Input, dict[str, Any]]: ...631632    @overload633    def __or__(634        self,635        other: Callable[[Output], Runnable[Output, Other]]636        | Callable[[Output], Awaitable[Runnable[Output, Other]]],637    ) -> RunnableSerializable[Input, Other]: ...638639    @overload640    def __or__(641        self,642        other: Runnable[Output, Other]643        | Callable[[Iterator[Output]], Iterator[Other]]644        | Callable[[AsyncIterator[Output]], AsyncIterator[Other]]645        | Callable[[Output], Other],646    ) -> RunnableSerializable[Input, Other]: ...647648    def __or__(649        self,650        other: Runnable[Output, Other]651        | Callable[[Iterator[Output]], Iterator[Other]]652        | Callable[[AsyncIterator[Output]], AsyncIterator[Other]]653        | Callable[[Output], Other]654        | Mapping[str, Runnable[Output, Any] | Callable[[Output], Any] | Any],655    ) -> RunnableSerializable[Input, Any]:656        """Runnable "or" operator.657658        Compose this `Runnable` with another object to create a659        `RunnableSequence`.660661        Args:662            other: Another `Runnable` or a `Runnable`-like object.663664        Returns:665            A new `Runnable`.666667        Raises:668            TypeError: If `other` cannot be coerced to a `Runnable`. This method does669                not return `NotImplemented`, to avoid delegating LCEL composition to670                unrelated reflected `|` implementations. To interoperate, implement671                `Runnable`, make the object callable, or define `__or__` on the left.672        """673        return RunnableSequence(self, coerce_to_runnable(other))674675    @overload676    def __ror__(677        self,678        other: Mapping[str, Any],679    ) -> RunnableSerializable[Any, Output]: ...680681    @overload682    def __ror__(683        self,684        other: Callable[[Other], Runnable[Other, Input]]685        | Callable[[Other], Awaitable[Runnable[Other, Input]]],686    ) -> RunnableSerializable[Other, Output]: ...687688    @overload689    def __ror__(690        self,691        other: Runnable[Other, Input]692        | Callable[[Iterator[Other]], Iterator[Input]]693        | Callable[[AsyncIterator[Other]], AsyncIterator[Input]]694        | Callable[[Other], Input],695    ) -> RunnableSerializable[Other, Output]: ...696697    def __ror__(698        self,699        other: Runnable[Other, Input]700        | Callable[[Iterator[Other]], Iterator[Input]]701        | Callable[[AsyncIterator[Other]], AsyncIterator[Input]]702        | Callable[[Other], Any]703        | Mapping[str, Runnable[Other, Input] | Callable[[Other], Any] | Any],704    ) -> RunnableSerializable[Any, Output]:705        """Runnable "reverse-or" operator.706707        Compose this `Runnable` with another object to create a708        `RunnableSequence`.709710        Args:711            other: Another `Runnable` or a `Runnable`-like object.712713        Returns:714            A new `Runnable`.715716        Raises:717            TypeError: If `other` cannot be coerced to a `Runnable`. This method does718                not return `NotImplemented`, to avoid delegating LCEL composition to719                unrelated reflected `|` implementations. To interoperate, implement720                `Runnable`, make the object callable, or define `__or__` on the left.721        """722        return RunnableSequence(coerce_to_runnable(other), self)723724    def pipe(725        self,726        *others: Runnable[Any, Other] | Callable[[Any], Other],727        name: str | None = None,728    ) -> RunnableSerializable[Input, Other]:729        """Pipe `Runnable` objects.730731        Compose this `Runnable` with `Runnable`-like objects to make a732        `RunnableSequence`.733734        Equivalent to `RunnableSequence(self, *others)` or `self | others[0] | ...`735736        Example:737            ```python738            from langchain_core.runnables import RunnableLambda739740741            def add_one(x: int) -> int:742                return x + 1743744745            def mul_two(x: int) -> int:746                return x * 2747748749            runnable_1 = RunnableLambda(add_one)750            runnable_2 = RunnableLambda(mul_two)751            sequence = runnable_1.pipe(runnable_2)752            # Or equivalently:753            # sequence = runnable_1 | runnable_2754            # sequence = RunnableSequence(first=runnable_1, last=runnable_2)755            sequence.invoke(1)756            await sequence.ainvoke(1)757            # -> 4758759            sequence.batch([1, 2, 3])760            await sequence.abatch([1, 2, 3])761            # -> [4, 6, 8]762            ```763764        Args:765            *others: Other `Runnable` or `Runnable`-like objects to compose766            name: An optional name for the resulting `RunnableSequence`.767768        Returns:769            A new `Runnable`.770        """771        return RunnableSequence(self, *others, name=name)772773    def pick(self, keys: str | list[str]) -> RunnableSerializable[Any, Any]:774        """Pick keys from the output `dict` of this `Runnable`.775776        !!! example "Pick a single key"777778            ```python779            import json780781            from langchain_core.runnables import RunnableLambda, RunnableMap782783            as_str = RunnableLambda(str)784            as_json = RunnableLambda(json.loads)785            chain = RunnableMap(str=as_str, json=as_json)786787            chain.invoke("[1, 2, 3]")788            # -> {"str": "[1, 2, 3]", "json": [1, 2, 3]}789790            json_only_chain = chain.pick("json")791            json_only_chain.invoke("[1, 2, 3]")792            # -> [1, 2, 3]793            ```794795        !!! example "Pick a list of keys"796797            ```python798            from typing import Any799800            import json801802            from langchain_core.runnables import RunnableLambda, RunnableMap803804            as_str = RunnableLambda(str)805            as_json = RunnableLambda(json.loads)806807808            def as_bytes(x: Any) -> bytes:809                return bytes(x, "utf-8")810811812            chain = RunnableMap(813                str=as_str, json=as_json, bytes=RunnableLambda(as_bytes)814            )815816            chain.invoke("[1, 2, 3]")817            # -> {"str": "[1, 2, 3]", "json": [1, 2, 3], "bytes": b"[1, 2, 3]"}818819            json_and_bytes_chain = chain.pick(["json", "bytes"])820            json_and_bytes_chain.invoke("[1, 2, 3]")821            # -> {"json": [1, 2, 3], "bytes": b"[1, 2, 3]"}822            ```823824        Args:825            keys: A key or list of keys to pick from the output dict.826827        Returns:828            a new `Runnable`.829830        """831        # Import locally to prevent circular import832        from langchain_core.runnables.passthrough import RunnablePick  # noqa: PLC0415833834        return self | RunnablePick(keys)  # type: ignore[operator, no-any-return]835836    def assign(837        self,838        **kwargs: Runnable[dict[str, Any], Any]839        | Callable[[dict[str, Any]], Any]840        | Mapping[str, Runnable[dict[str, Any], Any] | Callable[[dict[str, Any]], Any]],841    ) -> RunnableSerializable[Any, Any]:842        """Assigns new fields to the `dict` output of this `Runnable`.843844        ```python845        from langchain_core.language_models.fake import FakeStreamingListLLM846        from langchain_core.output_parsers import StrOutputParser847        from langchain_core.prompts import SystemMessagePromptTemplate848        from langchain_core.runnables import Runnable849        from operator import itemgetter850851        prompt = (852            SystemMessagePromptTemplate.from_template("You are a nice assistant.")853            + "{question}"854        )855        model = FakeStreamingListLLM(responses=["foo-lish"])856857        chain: Runnable = prompt | model | {"str": StrOutputParser()}858859        chain_with_assign = chain.assign(hello=itemgetter("str") | model)860861        print(chain_with_assign.input_schema.model_json_schema())862        # {'title': 'PromptInput', 'type': 'object', 'properties':863        {'question': {'title': 'Question', 'type': 'string'}}}864        print(chain_with_assign.output_schema.model_json_schema())865        # {'title': 'RunnableSequenceOutput', 'type': 'object', 'properties':866        {'str': {'title': 'Str',867        'type': 'string'}, 'hello': {'title': 'Hello', 'type': 'string'}}}868        ```869870        Args:871            **kwargs: A mapping of keys to `Runnable` or `Runnable`-like objects872                that will be invoked with the entire output dict of this `Runnable`.873874        Returns:875            A new `Runnable`.876877        """878        # Import locally to prevent circular import879        from langchain_core.runnables.passthrough import RunnableAssign  # noqa: PLC0415880881        return self | RunnableAssign(RunnableParallel[dict[str, Any]](kwargs))  # type: ignore[operator, no-any-return]882883    """ --- Public API --- """884885    @abstractmethod886    def invoke(887        self,888        input: Input,889        config: RunnableConfig | None = None,890        **kwargs: Any,891    ) -> Output:892        """Transform a single input into an output.893894        Args:895            input: The input to the `Runnable`.896            config: A config to use when invoking the `Runnable`.897898                The config supports standard keys like `'tags'`, `'metadata'` for899                tracing purposes, `'max_concurrency'` for controlling how much work to900                do in parallel, and other keys.901902                Please refer to `RunnableConfig` for more details.903904        Returns:905            The output of the `Runnable`.906        """907908    async def ainvoke(909        self,910        input: Input,911        config: RunnableConfig | None = None,912        **kwargs: Any,913    ) -> Output:914        """Transform a single input into an output.915916        Args:917            input: The input to the `Runnable`.918            config: A config to use when invoking the `Runnable`.919920                The config supports standard keys like `'tags'`, `'metadata'` for921                tracing purposes, `'max_concurrency'` for controlling how much work to922                do in parallel, and other keys.923924                Please refer to `RunnableConfig` for more details.925926        Returns:927            The output of the `Runnable`.928        """929        return await run_in_executor(config, self.invoke, input, config, **kwargs)930931    def batch(932        self,933        inputs: list[Input],934        config: RunnableConfig | list[RunnableConfig] | None = None,935        *,936        return_exceptions: bool = False,937        **kwargs: Any | None,938    ) -> list[Output]:939        """Default implementation runs invoke in parallel using a thread pool executor.940941        The default implementation of batch works well for IO bound runnables.942943        Subclasses must override this method if they can batch more efficiently;944        e.g., if the underlying `Runnable` uses an API which supports a batch mode.945946        Args:947            inputs: A list of inputs to the `Runnable`.948            config: A config to use when invoking the `Runnable`. The config supports949                standard keys like `'tags'`, `'metadata'` for950                tracing purposes, `'max_concurrency'` for controlling how much work951                to do in parallel, and other keys.952953                Please refer to `RunnableConfig` for more details.954            return_exceptions: Whether to return exceptions instead of raising them.955            **kwargs: Additional keyword arguments to pass to the `Runnable`.956957        Returns:958            A list of outputs from the `Runnable`.959        """960        if not inputs:961            return []962963        configs = get_config_list(config, len(inputs))964965        def invoke(input_: Input, config: RunnableConfig) -> Output | Exception:966            if return_exceptions:967                try:968                    return self.invoke(input_, config, **kwargs)969                except Exception as e:970                    return e971            else:972                return self.invoke(input_, config, **kwargs)973974        # If there's only one input, don't bother with the executor975        if len(inputs) == 1:976            return cast("list[Output]", [invoke(inputs[0], configs[0])])977978        with get_executor_for_config(configs[0]) as executor:979            return cast("list[Output]", list(executor.map(invoke, inputs, configs)))980981    @overload982    def batch_as_completed(983        self,984        inputs: Sequence[Input],985        config: RunnableConfig | Sequence[RunnableConfig] | None = None,986        *,987        return_exceptions: Literal[False] = False,988        **kwargs: Any,989    ) -> Iterator[tuple[int, Output]]: ...990991    @overload992    def batch_as_completed(993        self,994        inputs: Sequence[Input],995        config: RunnableConfig | Sequence[RunnableConfig] | None = None,996        *,997        return_exceptions: Literal[True],998        **kwargs: Any,999    ) -> Iterator[tuple[int, Output | Exception]]: ...10001001    def batch_as_completed(1002        self,1003        inputs: Sequence[Input],1004        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1005        *,1006        return_exceptions: bool = False,1007        **kwargs: Any | None,1008    ) -> Iterator[tuple[int, Output | Exception]]:1009        """Run `invoke` in parallel on a list of inputs.10101011        Yields results as they complete.10121013        Args:1014            inputs: A list of inputs to the `Runnable`.1015            config: A config to use when invoking the `Runnable`.10161017                The config supports standard keys like `'tags'`, `'metadata'` for1018                tracing purposes, `'max_concurrency'` for controlling how much work to1019                do in parallel, and other keys.10201021                Please refer to `RunnableConfig` for more details.1022            return_exceptions: Whether to return exceptions instead of raising them.1023            **kwargs: Additional keyword arguments to pass to the `Runnable`.10241025        Yields:1026            Tuples of the index of the input and the output from the `Runnable`.10271028        """1029        if not inputs:1030            return10311032        configs = get_config_list(config, len(inputs))10331034        def invoke(1035            i: int, input_: Input, config: RunnableConfig1036        ) -> tuple[int, Output | Exception]:1037            if return_exceptions:1038                try:1039                    out: Output | Exception = self.invoke(input_, config, **kwargs)1040                except Exception as e:1041                    out = e1042            else:1043                out = self.invoke(input_, config, **kwargs)10441045            return (i, out)10461047        if len(inputs) == 1:1048            yield invoke(0, inputs[0], configs[0])1049            return10501051        with get_executor_for_config(configs[0]) as executor:1052            futures = {1053                executor.submit(invoke, i, input_, config)1054                for i, (input_, config) in enumerate(zip(inputs, configs, strict=False))1055            }10561057            try:1058                while futures:1059                    done, futures = wait(futures, return_when=FIRST_COMPLETED)1060                    while done:1061                        yield done.pop().result()1062            finally:1063                for future in futures:1064                    future.cancel()10651066    async def abatch(1067        self,1068        inputs: list[Input],1069        config: RunnableConfig | list[RunnableConfig] | None = None,1070        *,1071        return_exceptions: bool = False,1072        **kwargs: Any | None,1073    ) -> list[Output]:1074        """Default implementation runs `ainvoke` in parallel using `asyncio.gather`.10751076        The default implementation of `batch` works well for IO bound runnables.10771078        Subclasses must override this method if they can batch more efficiently;1079        e.g., if the underlying `Runnable` uses an API which supports a batch mode.10801081        Args:1082            inputs: A list of inputs to the `Runnable`.1083            config: A config to use when invoking the `Runnable`.10841085                The config supports standard keys like `'tags'`, `'metadata'` for1086                tracing purposes, `'max_concurrency'` for controlling how much work to1087                do in parallel, and other keys.10881089                Please refer to `RunnableConfig` for more details.1090            return_exceptions: Whether to return exceptions instead of raising them.1091            **kwargs: Additional keyword arguments to pass to the `Runnable`.10921093        Returns:1094            A list of outputs from the `Runnable`.10951096        """1097        if not inputs:1098            return []10991100        configs = get_config_list(config, len(inputs))11011102        async def ainvoke(value: Input, config: RunnableConfig) -> Output | Exception:1103            if return_exceptions:1104                try:1105                    return await self.ainvoke(value, config, **kwargs)1106                except Exception as e:1107                    return e1108            else:1109                return await self.ainvoke(value, config, **kwargs)11101111        coros = map(ainvoke, inputs, configs)1112        return await gather_with_concurrency(configs[0].get("max_concurrency"), *coros)11131114    @overload1115    def abatch_as_completed(1116        self,1117        inputs: Sequence[Input],1118        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1119        *,1120        return_exceptions: Literal[False] = False,1121        **kwargs: Any | None,1122    ) -> AsyncIterator[tuple[int, Output]]: ...11231124    @overload1125    def abatch_as_completed(1126        self,1127        inputs: Sequence[Input],1128        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1129        *,1130        return_exceptions: Literal[True],1131        **kwargs: Any | None,1132    ) -> AsyncIterator[tuple[int, Output | Exception]]: ...11331134    async def abatch_as_completed(1135        self,1136        inputs: Sequence[Input],1137        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1138        *,1139        return_exceptions: bool = False,1140        **kwargs: Any | None,1141    ) -> AsyncIterator[tuple[int, Output | Exception]]:1142        """Run `ainvoke` in parallel on a list of inputs.11431144        Yields results as they complete.11451146        Args:1147            inputs: A list of inputs to the `Runnable`.1148            config: A config to use when invoking the `Runnable`.11491150                The config supports standard keys like `'tags'`, `'metadata'` for1151                tracing purposes, `'max_concurrency'` for controlling how much work to1152                do in parallel, and other keys.11531154                Please refer to `RunnableConfig` for more details.1155            return_exceptions: Whether to return exceptions instead of raising them.1156            **kwargs: Additional keyword arguments to pass to the `Runnable`.11571158        Yields:1159            A tuple of the index of the input and the output from the `Runnable`.11601161        """1162        if not inputs:1163            return11641165        configs = get_config_list(config, len(inputs))1166        # Get max_concurrency from first config, defaulting to None (unlimited)1167        max_concurrency = configs[0].get("max_concurrency") if configs else None1168        semaphore = asyncio.Semaphore(max_concurrency) if max_concurrency else None11691170        async def ainvoke_task(1171            i: int, input_: Input, config: RunnableConfig1172        ) -> tuple[int, Output | Exception]:1173            if return_exceptions:1174                try:1175                    out: Output | Exception = await self.ainvoke(1176                        input_, config, **kwargs1177                    )1178                except Exception as e:1179                    out = e1180            else:1181                out = await self.ainvoke(input_, config, **kwargs)1182            return (i, out)11831184        coros = [1185            gated_coro(semaphore, ainvoke_task(i, input_, config))1186            if semaphore1187            else ainvoke_task(i, input_, config)1188            for i, (input_, config) in enumerate(zip(inputs, configs, strict=False))1189        ]11901191        for coro in asyncio.as_completed(coros):1192            yield await coro11931194    def stream(1195        self,1196        input: Input,1197        config: RunnableConfig | None = None,1198        **kwargs: Any | None,1199    ) -> Iterator[Output]:1200        """Default implementation of `stream`, which calls `invoke`.12011202        Subclasses must override this method if they support streaming output.12031204        Args:1205            input: The input to the `Runnable`.1206            config: The config to use for the `Runnable`.1207            **kwargs: Additional keyword arguments to pass to the `Runnable`.12081209        Yields:1210            The output of the `Runnable`.12111212        """1213        yield self.invoke(input, config, **kwargs)12141215    async def astream(1216        self,1217        input: Input,1218        config: RunnableConfig | None = None,1219        **kwargs: Any | None,1220    ) -> AsyncIterator[Output]:1221        """Default implementation of `astream`, which calls `ainvoke`.12221223        Subclasses must override this method if they support streaming output.12241225        Args:1226            input: The input to the `Runnable`.1227            config: The config to use for the `Runnable`.1228            **kwargs: Additional keyword arguments to pass to the `Runnable`.12291230        Yields:1231            The output of the `Runnable`.12321233        """1234        yield await self.ainvoke(input, config, **kwargs)12351236    @overload1237    def astream_log(1238        self,1239        input: Any,1240        config: RunnableConfig | None = None,1241        *,1242        diff: Literal[True] = True,1243        with_streamed_output_list: bool = True,1244        include_names: Sequence[str] | None = None,1245        include_types: Sequence[str] | None = None,1246        include_tags: Sequence[str] | None = None,1247        exclude_names: Sequence[str] | None = None,1248        exclude_types: Sequence[str] | None = None,1249        exclude_tags: Sequence[str] | None = None,1250        **kwargs: Any,1251    ) -> AsyncIterator[RunLogPatch]: ...12521253    @overload1254    def astream_log(1255        self,1256        input: Any,1257        config: RunnableConfig | None = None,1258        *,1259        diff: Literal[False],1260        with_streamed_output_list: bool = True,1261        include_names: Sequence[str] | None = None,1262        include_types: Sequence[str] | None = None,1263        include_tags: Sequence[str] | None = None,1264        exclude_names: Sequence[str] | None = None,1265        exclude_types: Sequence[str] | None = None,1266        exclude_tags: Sequence[str] | None = None,1267        **kwargs: Any,1268    ) -> AsyncIterator[RunLog]: ...12691270    async def astream_log(1271        self,1272        input: Any,1273        config: RunnableConfig | None = None,1274        *,1275        diff: bool = True,1276        with_streamed_output_list: bool = True,1277        include_names: Sequence[str] | None = None,1278        include_types: Sequence[str] | None = None,1279        include_tags: Sequence[str] | None = None,1280        exclude_names: Sequence[str] | None = None,1281        exclude_types: Sequence[str] | None = None,1282        exclude_tags: Sequence[str] | None = None,1283        **kwargs: Any,1284    ) -> AsyncIterator[RunLogPatch] | AsyncIterator[RunLog]:1285        """Stream all output from a `Runnable`, as reported to the callback system.12861287        This includes all inner runs of LLMs, Retrievers, Tools, etc.12881289        Output is streamed as Log objects, which include a list of1290        Jsonpatch ops that describe how the state of the run has changed in each1291        step, and the final state of the run.12921293        The Jsonpatch ops can be applied in order to construct state.12941295        Args:1296            input: The input to the `Runnable`.1297            config: The config to use for the `Runnable`.1298            diff: Whether to yield diffs between each step or the current state.1299            with_streamed_output_list: Whether to yield the `streamed_output` list.1300            include_names: Only include logs with these names.1301            include_types: Only include logs with these types.1302            include_tags: Only include logs with these tags.1303            exclude_names: Exclude logs with these names.1304            exclude_types: Exclude logs with these types.1305            exclude_tags: Exclude logs with these tags.1306            **kwargs: Additional keyword arguments to pass to the `Runnable`.13071308        Yields:1309            A `RunLogPatch` or `RunLog` object.13101311        """1312        warn_deprecated(1313            since="1.3.3",1314            message=("astream_log is deprecated. Use astream instead."),1315            removal="2.0.0",1316        )1317        stream = LogStreamCallbackHandler(1318            auto_close=False,1319            include_names=include_names,1320            include_types=include_types,1321            include_tags=include_tags,1322            exclude_names=exclude_names,1323            exclude_types=exclude_types,1324            exclude_tags=exclude_tags,1325            _schema_format="original",1326        )13271328        # Mypy isn't resolving the overloads here1329        # Likely an issue b/c `self` is being passed through1330        # and it's can't map it to Runnable[Input,Output]?1331        async for item in _astream_log_implementation(  # type: ignore[call-overload]1332            self,1333            input,1334            config,1335            diff=diff,1336            stream=stream,1337            with_streamed_output_list=with_streamed_output_list,1338            **kwargs,1339        ):1340            yield item13411342    @overload1343    def astream_events(1344        self,1345        input: Any,1346        config: RunnableConfig | None = None,1347        *,1348        version: Literal["v1", "v2"] = "v2",1349        include_names: Sequence[str] | None = None,1350        include_types: Sequence[str] | None = None,1351        include_tags: Sequence[str] | None = None,1352        exclude_names: Sequence[str] | None = None,1353        exclude_types: Sequence[str] | None = None,1354        exclude_tags: Sequence[str] | None = None,1355        **kwargs: Any,1356    ) -> AsyncIterator[StreamEvent]: ...13571358    @overload1359    def astream_events(1360        self,1361        input: Any,1362        config: RunnableConfig | None = None,1363        *,1364        version: Literal["v3"],1365        **kwargs: Any,1366    ) -> Awaitable[Any]: ...13671368    def astream_events(1369        self,1370        input: Any,1371        config: RunnableConfig | None = None,1372        *,1373        version: Literal["v1", "v2", "v3"] = "v2",1374        include_names: Sequence[str] | None = None,1375        include_types: Sequence[str] | None = None,1376        include_tags: Sequence[str] | None = None,1377        exclude_names: Sequence[str] | None = None,1378        exclude_types: Sequence[str] | None = None,1379        exclude_tags: Sequence[str] | None = None,1380        **kwargs: Any,1381    ) -> AsyncIterator[StreamEvent] | Awaitable[Any]:1382        """Generate a stream of events.13831384        Use to create an iterator over `StreamEvent` that provide real-time information1385        about the progress of the `Runnable`, including `StreamEvent` from intermediate1386        results.13871388        A `StreamEvent` is a dictionary with the following schema:13891390        - `event`: Event names are of the format:1391            `on_[runnable_type]_(start|stream|end)`.1392        - `name`: The name of the `Runnable` that generated the event.1393        - `run_id`: Randomly generated ID associated with the given execution of the1394            `Runnable` that emitted the event. A child `Runnable` that gets invoked as1395            part of the execution of a parent `Runnable` is assigned its own unique ID.1396        - `parent_ids`: The IDs of the parent runnables that generated the event. The1397            root `Runnable` will have an empty list. The order of the parent IDs is from1398            the root to the immediate parent. Only available for v2 version of the API.1399            The v1 version of the API will return an empty list.1400        - `tags`: The tags of the `Runnable` that generated the event.1401        - `metadata`: The metadata of the `Runnable` that generated the event.1402        - `data`: The data associated with the event. The contents of this field1403            depend on the type of event. See the table below for more details.14041405        Below is a table that illustrates some events that might be emitted by various1406        chains. Metadata fields have been omitted from the table for brevity.1407        Chain definitions have been included after the table.14081409        !!! note1410            This reference table is for the v2 version of the schema.14111412        | event                  | name                 | chunk                               | input                                             | output                                              |1413        | ---------------------- | -------------------- | ----------------------------------- | ------------------------------------------------- | --------------------------------------------------- |1414        | `on_chat_model_start`  | `'[model name]'`     |                                     | `{"messages": [[SystemMessage, HumanMessage]]}`   |                                                     |1415        | `on_chat_model_stream` | `'[model name]'`     | `AIMessageChunk(content="hello")`   |                                                   |                                                     |1416        | `on_chat_model_end`    | `'[model name]'`     |                                     | `{"messages": [[SystemMessage, HumanMessage]]}`   | `AIMessageChunk(content="hello world")`             |1417        | `on_llm_start`         | `'[model name]'`     |                                     | `{'input': 'hello'}`                              |                                                     |1418        | `on_llm_stream`        | `'[model name]'`     | `'Hello' `                          |                                                   |                                                     |1419        | `on_llm_end`           | `'[model name]'`     |                                     | `'Hello human!'`                                  |                                                     |1420        | `on_chain_start`       | `'format_docs'`      |                                     |                                                   |                                                     |1421        | `on_chain_stream`      | `'format_docs'`      | `'hello world!, goodbye world!'`    |                                                   |                                                     |1422        | `on_chain_end`         | `'format_docs'`      |                                     | `[Document(...)]`                                 | `'hello world!, goodbye world!'`                    |1423        | `on_tool_start`        | `'some_tool'`        |                                     | `{"x": 1, "y": "2"}`                              |                                                     |1424        | `on_tool_end`          | `'some_tool'`        |                                     |                                                   | `{"x": 1, "y": "2"}`                                |1425        | `on_retriever_start`   | `'[retriever name]'` |                                     | `{"query": "hello"}`                              |                                                     |1426        | `on_retriever_end`     | `'[retriever name]'` |                                     | `{"query": "hello"}`                              | `[Document(...), ..]`                               |1427        | `on_prompt_start`      | `'[template_name]'`  |                                     | `{"question": "hello"}`                           |                                                     |1428        | `on_prompt_end`        | `'[template_name]'`  |                                     | `{"question": "hello"}`                           | `ChatPromptValue(messages: [SystemMessage, ...])`   |14291430        In addition to the standard events, users can also dispatch custom events (see example below).14311432        Custom events will be only be surfaced with in the v2 version of the API!14331434        A custom event has following format:14351436        | Attribute   | Type   | Description                                                                                               |1437        | ----------- | ------ | --------------------------------------------------------------------------------------------------------- |1438        | `name`      | `str`  | A user defined name for the event.                                                                        |1439        | `data`      | `Any`  | The data associated with the event. This can be anything, though we suggest making it JSON serializable.  |14401441        Here are declarations associated with the standard events shown above:14421443        `format_docs`:14441445        ```python1446        def format_docs(docs: list[Document]) -> str:1447            '''Format the docs.'''1448            return ", ".join([doc.page_content for doc in docs])144914501451        format_docs = RunnableLambda(format_docs)1452        ```14531454        `some_tool`:14551456        ```python1457        @tool1458        def some_tool(x: int, y: str) -> dict:1459            '''Some_tool.'''1460            return {"x": x, "y": y}1461        ```14621463        `prompt`:14641465        ```python1466        template = ChatPromptTemplate.from_messages(1467            [1468                ("system", "You are Cat Agent 007"),1469                ("human", "{question}"),1470            ]1471        ).with_config({"run_name": "my_template", "tags": ["my_template"]})1472        ```14731474        !!! example14751476            ```python1477            from langchain_core.runnables import RunnableLambda147814791480            async def reverse(s: str) -> str:1481                return s[::-1]148214831484            chain = RunnableLambda(func=reverse)14851486            events = [1487                event async for event in chain.astream_events("hello", version="v2")1488            ]14891490            # Will produce the following events1491            # (run_id, and parent_ids has been omitted for brevity):1492            [1493                {1494                    "data": {"input": "hello"},1495                    "event": "on_chain_start",1496                    "metadata": {},1497                    "name": "reverse",1498                    "tags": [],1499                },1500                {1501                    "data": {"chunk": "olleh"},1502                    "event": "on_chain_stream",1503                    "metadata": {},1504                    "name": "reverse",1505                    "tags": [],1506                },1507                {1508                    "data": {"output": "olleh"},1509                    "event": "on_chain_end",1510                    "metadata": {},1511                    "name": "reverse",1512                    "tags": [],1513                },1514            ]1515            ```15161517        ```python title="Dispatch custom event"1518        from langchain_core.callbacks.manager import (1519            adispatch_custom_event,1520        )1521        from langchain_core.runnables import RunnableLambda, RunnableConfig1522        import asyncio152315241525        async def slow_thing(some_input: str, config: RunnableConfig) -> str:1526            \"\"\"Do something that takes a long time.\"\"\"1527            await asyncio.sleep(1) # Placeholder for some slow operation1528            await adispatch_custom_event(1529                "progress_event",1530                {"message": "Finished step 1 of 3"},1531                config=config # Must be included for python < 3.101532            )1533            await asyncio.sleep(1) # Placeholder for some slow operation1534            await adispatch_custom_event(1535                "progress_event",1536                {"message": "Finished step 2 of 3"},1537                config=config # Must be included for python < 3.101538            )1539            await asyncio.sleep(1) # Placeholder for some slow operation1540            return "Done"15411542        slow_thing = RunnableLambda(slow_thing)15431544        async for event in slow_thing.astream_events("some_input", version="v2"):1545            print(event)1546        ```15471548        Args:1549            input: The input to the `Runnable`.1550            config: The config to use for the `Runnable`.1551            version: The version of the schema to use. One of `'v1'`, `'v2'`,1552                or `'v3'`.15531554                Most callers should use `'v2'` (the default), which yields1555                `StreamEvent` dicts and supports custom events.15561557                `'v3'` selects the typed, content-block-centric streaming1558                protocol and is only supported on `Runnable` subclasses that1559                implement it (currently `BaseChatModel` and1560                `langgraph.CompiledGraph`); on a generic `Runnable` it raises1561                `NotImplementedError`. The `'v3'` API is in beta and may1562                change. See the subclass override (e.g.1563                `BaseChatModel.astream_events`) for the v3 return shape.15641565                `'v1'` is retained for backwards compatibility and will be1566                deprecated in `0.4.0`. Custom events are only surfaced in1567                `'v2'` / `'v3'`.1568            include_names: Only include events from `Runnable` objects with matching names.1569            include_types: Only include events from `Runnable` objects with matching types.1570            include_tags: Only include events from `Runnable` objects with matching tags.1571            exclude_names: Exclude events from `Runnable` objects with matching names.1572            exclude_types: Exclude events from `Runnable` objects with matching types.1573            exclude_tags: Exclude events from `Runnable` objects with matching tags.1574            **kwargs: Additional keyword arguments to pass to the `Runnable`.15751576        Yields:1577            An async stream of `StreamEvent`.15781579        Raises:1580            NotImplementedError: If the version is not `'v1'`, `'v2'`, or `'v3'`, or1581                if `'v3'` is requested on a `Runnable` that does not implement the v31582                streaming protocol.15831584        """  # noqa: E5011585        if version == "v3":1586            return self._astream_events_v3_unsupported()1587        return self._astream_events_v1_v2(1588            input,1589            config=config,1590            version=version,1591            include_names=include_names,1592            include_types=include_types,1593            include_tags=include_tags,1594            exclude_names=exclude_names,1595            exclude_types=exclude_types,1596            exclude_tags=exclude_tags,1597            **kwargs,1598        )15991600    async def _astream_events_v3_unsupported(self) -> Any:1601        """Coroutine that raises when v3 isn't implemented on this Runnable.16021603        Lets the public `astream_events(version="v3")` return an awaitable1604        whose error surfaces on `await`, matching the v3 contract on1605        subclasses that do implement the protocol.1606        """1607        msg = (1608            "astream_events(version='v3') is only supported on Runnable "1609            "subclasses that implement the v3 streaming protocol "1610            "(BaseChatModel, CompiledGraph). "1611            f"Got: {type(self).__name__}"1612        )1613        raise NotImplementedError(msg)16141615    async def _astream_events_v1_v2(1616        self,1617        input: Any,1618        config: RunnableConfig | None = None,1619        *,1620        version: Literal["v1", "v2"] = "v2",1621        include_names: Sequence[str] | None = None,1622        include_types: Sequence[str] | None = None,1623        include_tags: Sequence[str] | None = None,1624        exclude_names: Sequence[str] | None = None,1625        exclude_types: Sequence[str] | None = None,1626        exclude_tags: Sequence[str] | None = None,1627        **kwargs: Any,1628    ) -> AsyncIterator[StreamEvent]:1629        if version == "v2":1630            event_stream = _astream_events_implementation_v2(1631                self,1632                input,1633                config=config,1634                include_names=include_names,1635                include_types=include_types,1636                include_tags=include_tags,1637                exclude_names=exclude_names,1638                exclude_types=exclude_types,1639                exclude_tags=exclude_tags,1640                **kwargs,1641            )1642        elif version == "v1":1643            warn_deprecated(1644                since="1.3.3",1645                message=(1646                    "astream_events version='v1' is deprecated. "1647                    "Use version='v2' or astream instead."1648                ),1649                removal="2.0.0",1650            )1651            # First implementation, built on top of astream_log API1652            # This implementation will be deprecated as of 0.2.01653            event_stream = _astream_events_implementation_v1(1654                self,1655                input,1656                config=config,1657                include_names=include_names,1658                include_types=include_types,1659                include_tags=include_tags,1660                exclude_names=exclude_names,1661                exclude_types=exclude_types,1662                exclude_tags=exclude_tags,1663                **kwargs,1664            )1665        else:1666            msg = f"Unsupported version: {version!r}. Expected 'v1', 'v2', or 'v3'."  # type: ignore[unreachable]1667            raise NotImplementedError(msg)16681669        async with aclosing(event_stream):1670            async for event in event_stream:1671                yield event16721673    @overload1674    def stream_events(1675        self,1676        input: Any,1677        config: RunnableConfig | None = None,1678        *,1679        version: Literal["v1", "v2"] = "v2",1680        include_names: Sequence[str] | None = None,1681        include_types: Sequence[str] | None = None,1682        include_tags: Sequence[str] | None = None,1683        exclude_names: Sequence[str] | None = None,1684        exclude_types: Sequence[str] | None = None,1685        exclude_tags: Sequence[str] | None = None,1686        **kwargs: Any,1687    ) -> Iterator[StreamEvent]: ...16881689    @overload1690    def stream_events(1691        self,1692        input: Any,1693        config: RunnableConfig | None = None,1694        *,1695        version: Literal["v3"],1696        **kwargs: Any,1697    ) -> Iterator[Any]: ...16981699    def stream_events(1700        self,1701        input: Any,1702        config: RunnableConfig | None = None,1703        *,1704        version: Literal["v1", "v2", "v3"] = "v2",1705        include_names: Sequence[str] | None = None,1706        include_types: Sequence[str] | None = None,1707        include_tags: Sequence[str] | None = None,1708        exclude_names: Sequence[str] | None = None,1709        exclude_types: Sequence[str] | None = None,1710        exclude_tags: Sequence[str] | None = None,1711        **kwargs: Any,1712    ) -> Iterator[StreamEvent] | Iterator[Any]:1713        """Generate a stream of events synchronously.17141715        Synchronous counterpart to `astream_events`. For `version='v3'`, subclasses1716        that implement the v3 streaming protocol (`BaseChatModel`, `CompiledGraph`)1717        override this method. All other versions and base-class calls raise1718        `NotImplementedError`.17191720        Args:1721            input: The input to the `Runnable`.1722            config: The config to use for the `Runnable`.1723            version: The version of the schema to use. `'v3'` requires a subclass1724                that implements the v3 streaming protocol. `'v1'` and `'v2'` are not1725                supported on the sync path.1726            include_names: Only include events from `Runnable` objects with matching1727                names.1728            include_types: Only include events from `Runnable` objects with matching1729                types.1730            include_tags: Only include events from `Runnable` objects with matching1731                tags.1732            exclude_names: Exclude events from `Runnable` objects with matching names.1733            exclude_types: Exclude events from `Runnable` objects with matching types.1734            exclude_tags: Exclude events from `Runnable` objects with matching tags.1735            **kwargs: Additional keyword arguments to pass to the `Runnable`.17361737        Raises:1738            NotImplementedError: Always. Subclasses override this method for supported1739                versions.17401741        """1742        # Base impl always raises; consume args so they don't trip ARG002.1743        del input, config, include_names, include_types, include_tags1744        del exclude_names, exclude_types, exclude_tags, kwargs1745        if version == "v3":1746            msg = (1747                "stream_events(version='v3') is only supported on Runnable subclasses "1748                "that implement the v3 streaming protocol "1749                "(BaseChatModel, CompiledGraph). "1750                f"Got: {type(self).__name__}"1751            )1752            raise NotImplementedError(msg)1753        msg = (1754            f"stream_events(version={version!r}) is not supported. "1755            "Use astream_events() for v1/v2, or stream_events(version='v3') "1756            "on a supported subclass."1757        )1758        raise NotImplementedError(msg)17591760    def transform(1761        self,1762        input: Iterator[Input],1763        config: RunnableConfig | None = None,1764        **kwargs: Any | None,1765    ) -> Iterator[Output]:1766        """Transform inputs to outputs.17671768        Default implementation of transform, which buffers input and calls `astream`.17691770        Subclasses must override this method if they can start producing output while1771        input is still being generated.17721773        Args:1774            input: An iterator of inputs to the `Runnable`.1775            config: The config to use for the `Runnable`.1776            **kwargs: Additional keyword arguments to pass to the `Runnable`.17771778        Yields:1779            The output of the `Runnable`.17801781        """1782        final: Input1783        got_first_val = False17841785        for ichunk in input:1786            # The default implementation of transform is to buffer input and1787            # then call stream.1788            # It'll attempt to gather all input into a single chunk using1789            # the `+` operator.1790            # If the input is not addable, then we'll assume that we can1791            # only operate on the last chunk,1792            # and we'll iterate until we get to the last chunk.1793            if not got_first_val:1794                final = ichunk1795                got_first_val = True1796            else:1797                try:1798                    final = final + ichunk  # type: ignore[operator]1799                except TypeError:1800                    final = ichunk18011802        if got_first_val:1803            yield from self.stream(final, config, **kwargs)18041805    async def atransform(1806        self,1807        input: AsyncIterator[Input],1808        config: RunnableConfig | None = None,1809        **kwargs: Any | None,1810    ) -> AsyncIterator[Output]:1811        """Transform inputs to outputs.18121813        Default implementation of atransform, which buffers input and calls `astream`.18141815        Subclasses must override this method if they can start producing output while1816        input is still being generated.18171818        Args:1819            input: An async iterator of inputs to the `Runnable`.1820            config: The config to use for the `Runnable`.1821            **kwargs: Additional keyword arguments to pass to the `Runnable`.18221823        Yields:1824            The output of the `Runnable`.18251826        """1827        final: Input1828        got_first_val = False18291830        async for ichunk in input:1831            # The default implementation of transform is to buffer input and1832            # then call stream.1833            # It'll attempt to gather all input into a single chunk using1834            # the `+` operator.1835            # If the input is not addable, then we'll assume that we can1836            # only operate on the last chunk,1837            # and we'll iterate until we get to the last chunk.1838            if not got_first_val:1839                final = ichunk1840                got_first_val = True1841            else:1842                try:1843                    final = final + ichunk  # type: ignore[operator]1844                except TypeError:1845                    final = ichunk18461847        if got_first_val:1848            async for output in self.astream(final, config, **kwargs):1849                yield output18501851    def bind(self, **kwargs: Any) -> Runnable[Input, Output]:1852        """Bind arguments to a `Runnable`, returning a new `Runnable`.18531854        Useful when a `Runnable` in a chain requires an argument that is not1855        in the output of the previous `Runnable` or included in the user input.18561857        Args:1858            **kwargs: The arguments to bind to the `Runnable`.18591860        Returns:1861            A new `Runnable` with the arguments bound.18621863        Example:1864            ```python1865            from langchain_ollama import ChatOllama1866            from langchain_core.output_parsers import StrOutputParser18671868            model = ChatOllama(model="llama3.1")18691870            # Without bind1871            chain = model | StrOutputParser()18721873            chain.invoke("Repeat quoted words exactly: 'One two three four five.'")1874            # Output is 'One two three four five.'18751876            # With bind1877            chain = model.bind(stop=["three"]) | StrOutputParser()18781879            chain.invoke("Repeat quoted words exactly: 'One two three four five.'")1880            # Output is 'One two'1881            ```1882        """1883        return RunnableBinding(bound=self, kwargs=kwargs, config={})18841885    def with_config(1886        self,1887        config: RunnableConfig | None = None,1888        # Sadly Unpack is not well-supported by mypy so this will have to be untyped1889        **kwargs: Any,1890    ) -> Runnable[Input, Output]:1891        """Bind config to a `Runnable`, returning a new `Runnable`.18921893        Args:1894            config: The config to bind to the `Runnable`.1895            **kwargs: Additional keyword arguments to pass to the `Runnable`.18961897        Returns:1898            A new `Runnable` with the config bound.18991900        """1901        return RunnableBinding(1902            bound=self,1903            config=cast(1904                "RunnableConfig",1905                {**(config or {}), **kwargs},1906            ),1907            kwargs={},1908        )19091910    def with_listeners(1911        self,1912        *,1913        on_start: Callable[[Run], None]1914        | Callable[[Run, RunnableConfig], None]1915        | None = None,1916        on_end: Callable[[Run], None]1917        | Callable[[Run, RunnableConfig], None]1918        | None = None,1919        on_error: Callable[[Run], None]1920        | Callable[[Run, RunnableConfig], None]1921        | None = None,1922    ) -> Runnable[Input, Output]:1923        """Bind lifecycle listeners to a `Runnable`, returning a new `Runnable`.19241925        The Run object contains information about the run, including its `id`,1926        `type`, `input`, `output`, `error`, `start_time`, `end_time`, and1927        any tags or metadata added to the run.19281929        Args:1930            on_start: Called before the `Runnable` starts running, with the `Run`1931                object.1932            on_end: Called after the `Runnable` finishes running, with the `Run`1933                object.1934            on_error: Called if the `Runnable` throws an error, with the `Run`1935                object.19361937        Returns:1938            A new `Runnable` with the listeners bound.19391940        Example:1941            ```python1942            from langchain_core.runnables import RunnableLambda1943            from langchain_core.tracers.schemas import Run19441945            import time194619471948            def test_runnable(time_to_sleep: int):1949                time.sleep(time_to_sleep)195019511952            def fn_start(run_obj: Run):1953                print("start_time:", run_obj.start_time)195419551956            def fn_end(run_obj: Run):1957                print("end_time:", run_obj.end_time)195819591960            chain = RunnableLambda(test_runnable).with_listeners(1961                on_start=fn_start, on_end=fn_end1962            )1963            chain.invoke(2)1964            ```1965        """1966        return RunnableBinding(1967            bound=self,1968            config_factories=[1969                lambda config: {1970                    "callbacks": [1971                        RootListenersTracer(1972                            config=config,1973                            on_start=on_start,1974                            on_end=on_end,1975                            on_error=on_error,1976                        )1977                    ],1978                }1979            ],1980        )19811982    def with_alisteners(1983        self,1984        *,1985        on_start: AsyncListener | None = None,1986        on_end: AsyncListener | None = None,1987        on_error: AsyncListener | None = None,1988    ) -> Runnable[Input, Output]:1989        """Bind async lifecycle listeners to a `Runnable`.19901991        Returns a new `Runnable`.19921993        The Run object contains information about the run, including its `id`,1994        `type`, `input`, `output`, `error`, `start_time`, `end_time`, and1995        any tags or metadata added to the run.19961997        Args:1998            on_start: Called asynchronously before the `Runnable` starts running,1999                with the `Run` object.2000            on_end: Called asynchronously after the `Runnable` finishes running,

Findings

✓ No findings reported for this file.

Get this view in your editor

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