libs/core/langchain_core/runnables/base.py PYTHON 6,716 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 6,716.
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`.666        """667        return RunnableSequence(self, coerce_to_runnable(other))668669    @overload670    def __ror__(671        self,672        other: Mapping[str, Any],673    ) -> RunnableSerializable[Any, Output]: ...674675    @overload676    def __ror__(677        self,678        other: Callable[[Other], Runnable[Other, Input]]679        | Callable[[Other], Awaitable[Runnable[Other, Input]]],680    ) -> RunnableSerializable[Other, Output]: ...681682    @overload683    def __ror__(684        self,685        other: Runnable[Other, Input]686        | Callable[[Iterator[Other]], Iterator[Input]]687        | Callable[[AsyncIterator[Other]], AsyncIterator[Input]]688        | Callable[[Other], Input],689    ) -> RunnableSerializable[Other, Output]: ...690691    def __ror__(692        self,693        other: Runnable[Other, Input]694        | Callable[[Iterator[Other]], Iterator[Input]]695        | Callable[[AsyncIterator[Other]], AsyncIterator[Input]]696        | Callable[[Other], Any]697        | Mapping[str, Runnable[Other, Input] | Callable[[Other], Any] | Any],698    ) -> RunnableSerializable[Any, Output]:699        """Runnable "reverse-or" operator.700701        Compose this `Runnable` with another object to create a702        `RunnableSequence`.703704        Args:705            other: Another `Runnable` or a `Runnable`-like object.706707        Returns:708            A new `Runnable`.709        """710        return RunnableSequence(coerce_to_runnable(other), self)711712    def pipe(713        self,714        *others: Runnable[Any, Other] | Callable[[Any], Other],715        name: str | None = None,716    ) -> RunnableSerializable[Input, Other]:717        """Pipe `Runnable` objects.718719        Compose this `Runnable` with `Runnable`-like objects to make a720        `RunnableSequence`.721722        Equivalent to `RunnableSequence(self, *others)` or `self | others[0] | ...`723724        Example:725            ```python726            from langchain_core.runnables import RunnableLambda727728729            def add_one(x: int) -> int:730                return x + 1731732733            def mul_two(x: int) -> int:734                return x * 2735736737            runnable_1 = RunnableLambda(add_one)738            runnable_2 = RunnableLambda(mul_two)739            sequence = runnable_1.pipe(runnable_2)740            # Or equivalently:741            # sequence = runnable_1 | runnable_2742            # sequence = RunnableSequence(first=runnable_1, last=runnable_2)743            sequence.invoke(1)744            await sequence.ainvoke(1)745            # -> 4746747            sequence.batch([1, 2, 3])748            await sequence.abatch([1, 2, 3])749            # -> [4, 6, 8]750            ```751752        Args:753            *others: Other `Runnable` or `Runnable`-like objects to compose754            name: An optional name for the resulting `RunnableSequence`.755756        Returns:757            A new `Runnable`.758        """759        return RunnableSequence(self, *others, name=name)760761    def pick(self, keys: str | list[str]) -> RunnableSerializable[Any, Any]:762        """Pick keys from the output `dict` of this `Runnable`.763764        !!! example "Pick a single key"765766            ```python767            import json768769            from langchain_core.runnables import RunnableLambda, RunnableMap770771            as_str = RunnableLambda(str)772            as_json = RunnableLambda(json.loads)773            chain = RunnableMap(str=as_str, json=as_json)774775            chain.invoke("[1, 2, 3]")776            # -> {"str": "[1, 2, 3]", "json": [1, 2, 3]}777778            json_only_chain = chain.pick("json")779            json_only_chain.invoke("[1, 2, 3]")780            # -> [1, 2, 3]781            ```782783        !!! example "Pick a list of keys"784785            ```python786            from typing import Any787788            import json789790            from langchain_core.runnables import RunnableLambda, RunnableMap791792            as_str = RunnableLambda(str)793            as_json = RunnableLambda(json.loads)794795796            def as_bytes(x: Any) -> bytes:797                return bytes(x, "utf-8")798799800            chain = RunnableMap(801                str=as_str, json=as_json, bytes=RunnableLambda(as_bytes)802            )803804            chain.invoke("[1, 2, 3]")805            # -> {"str": "[1, 2, 3]", "json": [1, 2, 3], "bytes": b"[1, 2, 3]"}806807            json_and_bytes_chain = chain.pick(["json", "bytes"])808            json_and_bytes_chain.invoke("[1, 2, 3]")809            # -> {"json": [1, 2, 3], "bytes": b"[1, 2, 3]"}810            ```811812        Args:813            keys: A key or list of keys to pick from the output dict.814815        Returns:816            a new `Runnable`.817818        """819        # Import locally to prevent circular import820        from langchain_core.runnables.passthrough import RunnablePick  # noqa: PLC0415821822        return self | RunnablePick(keys)  # type: ignore[operator, no-any-return]823824    def assign(825        self,826        **kwargs: Runnable[dict[str, Any], Any]827        | Callable[[dict[str, Any]], Any]828        | Mapping[str, Runnable[dict[str, Any], Any] | Callable[[dict[str, Any]], Any]],829    ) -> RunnableSerializable[Any, Any]:830        """Assigns new fields to the `dict` output of this `Runnable`.831832        ```python833        from langchain_core.language_models.fake import FakeStreamingListLLM834        from langchain_core.output_parsers import StrOutputParser835        from langchain_core.prompts import SystemMessagePromptTemplate836        from langchain_core.runnables import Runnable837        from operator import itemgetter838839        prompt = (840            SystemMessagePromptTemplate.from_template("You are a nice assistant.")841            + "{question}"842        )843        model = FakeStreamingListLLM(responses=["foo-lish"])844845        chain: Runnable = prompt | model | {"str": StrOutputParser()}846847        chain_with_assign = chain.assign(hello=itemgetter("str") | model)848849        print(chain_with_assign.input_schema.model_json_schema())850        # {'title': 'PromptInput', 'type': 'object', 'properties':851        {'question': {'title': 'Question', 'type': 'string'}}}852        print(chain_with_assign.output_schema.model_json_schema())853        # {'title': 'RunnableSequenceOutput', 'type': 'object', 'properties':854        {'str': {'title': 'Str',855        'type': 'string'}, 'hello': {'title': 'Hello', 'type': 'string'}}}856        ```857858        Args:859            **kwargs: A mapping of keys to `Runnable` or `Runnable`-like objects860                that will be invoked with the entire output dict of this `Runnable`.861862        Returns:863            A new `Runnable`.864865        """866        # Import locally to prevent circular import867        from langchain_core.runnables.passthrough import RunnableAssign  # noqa: PLC0415868869        return self | RunnableAssign(RunnableParallel[dict[str, Any]](kwargs))  # type: ignore[operator, no-any-return]870871    """ --- Public API --- """872873    @abstractmethod874    def invoke(875        self,876        input: Input,877        config: RunnableConfig | None = None,878        **kwargs: Any,879    ) -> Output:880        """Transform a single input into an output.881882        Args:883            input: The input to the `Runnable`.884            config: A config to use when invoking the `Runnable`.885886                The config supports standard keys like `'tags'`, `'metadata'` for887                tracing purposes, `'max_concurrency'` for controlling how much work to888                do in parallel, and other keys.889890                Please refer to `RunnableConfig` for more details.891892        Returns:893            The output of the `Runnable`.894        """895896    async def ainvoke(897        self,898        input: Input,899        config: RunnableConfig | None = None,900        **kwargs: Any,901    ) -> Output:902        """Transform a single input into an output.903904        Args:905            input: The input to the `Runnable`.906            config: A config to use when invoking the `Runnable`.907908                The config supports standard keys like `'tags'`, `'metadata'` for909                tracing purposes, `'max_concurrency'` for controlling how much work to910                do in parallel, and other keys.911912                Please refer to `RunnableConfig` for more details.913914        Returns:915            The output of the `Runnable`.916        """917        return await run_in_executor(config, self.invoke, input, config, **kwargs)918919    def batch(920        self,921        inputs: list[Input],922        config: RunnableConfig | list[RunnableConfig] | None = None,923        *,924        return_exceptions: bool = False,925        **kwargs: Any | None,926    ) -> list[Output]:927        """Default implementation runs invoke in parallel using a thread pool executor.928929        The default implementation of batch works well for IO bound runnables.930931        Subclasses must override this method if they can batch more efficiently;932        e.g., if the underlying `Runnable` uses an API which supports a batch mode.933934        Args:935            inputs: A list of inputs to the `Runnable`.936            config: A config to use when invoking the `Runnable`. The config supports937                standard keys like `'tags'`, `'metadata'` for938                tracing purposes, `'max_concurrency'` for controlling how much work939                to do in parallel, and other keys.940941                Please refer to `RunnableConfig` for more details.942            return_exceptions: Whether to return exceptions instead of raising them.943            **kwargs: Additional keyword arguments to pass to the `Runnable`.944945        Returns:946            A list of outputs from the `Runnable`.947        """948        if not inputs:949            return []950951        configs = get_config_list(config, len(inputs))952953        def invoke(input_: Input, config: RunnableConfig) -> Output | Exception:954            if return_exceptions:955                try:956                    return self.invoke(input_, config, **kwargs)957                except Exception as e:958                    return e959            else:960                return self.invoke(input_, config, **kwargs)961962        # If there's only one input, don't bother with the executor963        if len(inputs) == 1:964            return cast("list[Output]", [invoke(inputs[0], configs[0])])965966        with get_executor_for_config(configs[0]) as executor:967            return cast("list[Output]", list(executor.map(invoke, inputs, configs)))968969    @overload970    def batch_as_completed(971        self,972        inputs: Sequence[Input],973        config: RunnableConfig | Sequence[RunnableConfig] | None = None,974        *,975        return_exceptions: Literal[False] = False,976        **kwargs: Any,977    ) -> Iterator[tuple[int, Output]]: ...978979    @overload980    def batch_as_completed(981        self,982        inputs: Sequence[Input],983        config: RunnableConfig | Sequence[RunnableConfig] | None = None,984        *,985        return_exceptions: Literal[True],986        **kwargs: Any,987    ) -> Iterator[tuple[int, Output | Exception]]: ...988989    def batch_as_completed(990        self,991        inputs: Sequence[Input],992        config: RunnableConfig | Sequence[RunnableConfig] | None = None,993        *,994        return_exceptions: bool = False,995        **kwargs: Any | None,996    ) -> Iterator[tuple[int, Output | Exception]]:997        """Run `invoke` in parallel on a list of inputs.998999        Yields results as they complete.10001001        Args:1002            inputs: A list of inputs to the `Runnable`.1003            config: A config to use when invoking the `Runnable`.10041005                The config supports standard keys like `'tags'`, `'metadata'` for1006                tracing purposes, `'max_concurrency'` for controlling how much work to1007                do in parallel, and other keys.10081009                Please refer to `RunnableConfig` for more details.1010            return_exceptions: Whether to return exceptions instead of raising them.1011            **kwargs: Additional keyword arguments to pass to the `Runnable`.10121013        Yields:1014            Tuples of the index of the input and the output from the `Runnable`.10151016        """1017        if not inputs:1018            return10191020        configs = get_config_list(config, len(inputs))10211022        def invoke(1023            i: int, input_: Input, config: RunnableConfig1024        ) -> tuple[int, Output | Exception]:1025            if return_exceptions:1026                try:1027                    out: Output | Exception = self.invoke(input_, config, **kwargs)1028                except Exception as e:1029                    out = e1030            else:1031                out = self.invoke(input_, config, **kwargs)10321033            return (i, out)10341035        if len(inputs) == 1:1036            yield invoke(0, inputs[0], configs[0])1037            return10381039        with get_executor_for_config(configs[0]) as executor:1040            futures = {1041                executor.submit(invoke, i, input_, config)1042                for i, (input_, config) in enumerate(zip(inputs, configs, strict=False))1043            }10441045            try:1046                while futures:1047                    done, futures = wait(futures, return_when=FIRST_COMPLETED)1048                    while done:1049                        yield done.pop().result()1050            finally:1051                for future in futures:1052                    future.cancel()10531054    async def abatch(1055        self,1056        inputs: list[Input],1057        config: RunnableConfig | list[RunnableConfig] | None = None,1058        *,1059        return_exceptions: bool = False,1060        **kwargs: Any | None,1061    ) -> list[Output]:1062        """Default implementation runs `ainvoke` in parallel using `asyncio.gather`.10631064        The default implementation of `batch` works well for IO bound runnables.10651066        Subclasses must override this method if they can batch more efficiently;1067        e.g., if the underlying `Runnable` uses an API which supports a batch mode.10681069        Args:1070            inputs: A list of inputs to the `Runnable`.1071            config: A config to use when invoking the `Runnable`.10721073                The config supports standard keys like `'tags'`, `'metadata'` for1074                tracing purposes, `'max_concurrency'` for controlling how much work to1075                do in parallel, and other keys.10761077                Please refer to `RunnableConfig` for more details.1078            return_exceptions: Whether to return exceptions instead of raising them.1079            **kwargs: Additional keyword arguments to pass to the `Runnable`.10801081        Returns:1082            A list of outputs from the `Runnable`.10831084        """1085        if not inputs:1086            return []10871088        configs = get_config_list(config, len(inputs))10891090        async def ainvoke(value: Input, config: RunnableConfig) -> Output | Exception:1091            if return_exceptions:1092                try:1093                    return await self.ainvoke(value, config, **kwargs)1094                except Exception as e:1095                    return e1096            else:1097                return await self.ainvoke(value, config, **kwargs)10981099        coros = map(ainvoke, inputs, configs)1100        return await gather_with_concurrency(configs[0].get("max_concurrency"), *coros)11011102    @overload1103    def abatch_as_completed(1104        self,1105        inputs: Sequence[Input],1106        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1107        *,1108        return_exceptions: Literal[False] = False,1109        **kwargs: Any | None,1110    ) -> AsyncIterator[tuple[int, Output]]: ...11111112    @overload1113    def abatch_as_completed(1114        self,1115        inputs: Sequence[Input],1116        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1117        *,1118        return_exceptions: Literal[True],1119        **kwargs: Any | None,1120    ) -> AsyncIterator[tuple[int, Output | Exception]]: ...11211122    async def abatch_as_completed(1123        self,1124        inputs: Sequence[Input],1125        config: RunnableConfig | Sequence[RunnableConfig] | None = None,1126        *,1127        return_exceptions: bool = False,1128        **kwargs: Any | None,1129    ) -> AsyncIterator[tuple[int, Output | Exception]]:1130        """Run `ainvoke` in parallel on a list of inputs.11311132        Yields results as they complete.11331134        Args:1135            inputs: A list of inputs to the `Runnable`.1136            config: A config to use when invoking the `Runnable`.11371138                The config supports standard keys like `'tags'`, `'metadata'` for1139                tracing purposes, `'max_concurrency'` for controlling how much work to1140                do in parallel, and other keys.11411142                Please refer to `RunnableConfig` for more details.1143            return_exceptions: Whether to return exceptions instead of raising them.1144            **kwargs: Additional keyword arguments to pass to the `Runnable`.11451146        Yields:1147            A tuple of the index of the input and the output from the `Runnable`.11481149        """1150        if not inputs:1151            return11521153        configs = get_config_list(config, len(inputs))1154        # Get max_concurrency from first config, defaulting to None (unlimited)1155        max_concurrency = configs[0].get("max_concurrency") if configs else None1156        semaphore = asyncio.Semaphore(max_concurrency) if max_concurrency else None11571158        async def ainvoke_task(1159            i: int, input_: Input, config: RunnableConfig1160        ) -> tuple[int, Output | Exception]:1161            if return_exceptions:1162                try:1163                    out: Output | Exception = await self.ainvoke(1164                        input_, config, **kwargs1165                    )1166                except Exception as e:1167                    out = e1168            else:1169                out = await self.ainvoke(input_, config, **kwargs)1170            return (i, out)11711172        coros = [1173            gated_coro(semaphore, ainvoke_task(i, input_, config))1174            if semaphore1175            else ainvoke_task(i, input_, config)1176            for i, (input_, config) in enumerate(zip(inputs, configs, strict=False))1177        ]11781179        for coro in asyncio.as_completed(coros):1180            yield await coro11811182    def stream(1183        self,1184        input: Input,1185        config: RunnableConfig | None = None,1186        **kwargs: Any | None,1187    ) -> Iterator[Output]:1188        """Default implementation of `stream`, which calls `invoke`.11891190        Subclasses must override this method if they support streaming output.11911192        Args:1193            input: The input to the `Runnable`.1194            config: The config to use for the `Runnable`.1195            **kwargs: Additional keyword arguments to pass to the `Runnable`.11961197        Yields:1198            The output of the `Runnable`.11991200        """1201        yield self.invoke(input, config, **kwargs)12021203    async def astream(1204        self,1205        input: Input,1206        config: RunnableConfig | None = None,1207        **kwargs: Any | None,1208    ) -> AsyncIterator[Output]:1209        """Default implementation of `astream`, which calls `ainvoke`.12101211        Subclasses must override this method if they support streaming output.12121213        Args:1214            input: The input to the `Runnable`.1215            config: The config to use for the `Runnable`.1216            **kwargs: Additional keyword arguments to pass to the `Runnable`.12171218        Yields:1219            The output of the `Runnable`.12201221        """1222        yield await self.ainvoke(input, config, **kwargs)12231224    @overload1225    def astream_log(1226        self,1227        input: Any,1228        config: RunnableConfig | None = None,1229        *,1230        diff: Literal[True] = True,1231        with_streamed_output_list: bool = True,1232        include_names: Sequence[str] | None = None,1233        include_types: Sequence[str] | None = None,1234        include_tags: Sequence[str] | None = None,1235        exclude_names: Sequence[str] | None = None,1236        exclude_types: Sequence[str] | None = None,1237        exclude_tags: Sequence[str] | None = None,1238        **kwargs: Any,1239    ) -> AsyncIterator[RunLogPatch]: ...12401241    @overload1242    def astream_log(1243        self,1244        input: Any,1245        config: RunnableConfig | None = None,1246        *,1247        diff: Literal[False],1248        with_streamed_output_list: bool = True,1249        include_names: Sequence[str] | None = None,1250        include_types: Sequence[str] | None = None,1251        include_tags: Sequence[str] | None = None,1252        exclude_names: Sequence[str] | None = None,1253        exclude_types: Sequence[str] | None = None,1254        exclude_tags: Sequence[str] | None = None,1255        **kwargs: Any,1256    ) -> AsyncIterator[RunLog]: ...12571258    async def astream_log(1259        self,1260        input: Any,1261        config: RunnableConfig | None = None,1262        *,1263        diff: bool = True,1264        with_streamed_output_list: bool = True,1265        include_names: Sequence[str] | None = None,1266        include_types: Sequence[str] | None = None,1267        include_tags: Sequence[str] | None = None,1268        exclude_names: Sequence[str] | None = None,1269        exclude_types: Sequence[str] | None = None,1270        exclude_tags: Sequence[str] | None = None,1271        **kwargs: Any,1272    ) -> AsyncIterator[RunLogPatch] | AsyncIterator[RunLog]:1273        """Stream all output from a `Runnable`, as reported to the callback system.12741275        This includes all inner runs of LLMs, Retrievers, Tools, etc.12761277        Output is streamed as Log objects, which include a list of1278        Jsonpatch ops that describe how the state of the run has changed in each1279        step, and the final state of the run.12801281        The Jsonpatch ops can be applied in order to construct state.12821283        Args:1284            input: The input to the `Runnable`.1285            config: The config to use for the `Runnable`.1286            diff: Whether to yield diffs between each step or the current state.1287            with_streamed_output_list: Whether to yield the `streamed_output` list.1288            include_names: Only include logs with these names.1289            include_types: Only include logs with these types.1290            include_tags: Only include logs with these tags.1291            exclude_names: Exclude logs with these names.1292            exclude_types: Exclude logs with these types.1293            exclude_tags: Exclude logs with these tags.1294            **kwargs: Additional keyword arguments to pass to the `Runnable`.12951296        Yields:1297            A `RunLogPatch` or `RunLog` object.12981299        """1300        warn_deprecated(1301            since="1.3.3",1302            message=("astream_log is deprecated. Use astream instead."),1303            removal="2.0.0",1304        )1305        stream = LogStreamCallbackHandler(1306            auto_close=False,1307            include_names=include_names,1308            include_types=include_types,1309            include_tags=include_tags,1310            exclude_names=exclude_names,1311            exclude_types=exclude_types,1312            exclude_tags=exclude_tags,1313            _schema_format="original",1314        )13151316        # Mypy isn't resolving the overloads here1317        # Likely an issue b/c `self` is being passed through1318        # and it's can't map it to Runnable[Input,Output]?1319        async for item in _astream_log_implementation(  # type: ignore[call-overload]1320            self,1321            input,1322            config,1323            diff=diff,1324            stream=stream,1325            with_streamed_output_list=with_streamed_output_list,1326            **kwargs,1327        ):1328            yield item13291330    @overload1331    def astream_events(1332        self,1333        input: Any,1334        config: RunnableConfig | None = None,1335        *,1336        version: Literal["v1", "v2"] = "v2",1337        include_names: Sequence[str] | None = None,1338        include_types: Sequence[str] | None = None,1339        include_tags: Sequence[str] | None = None,1340        exclude_names: Sequence[str] | None = None,1341        exclude_types: Sequence[str] | None = None,1342        exclude_tags: Sequence[str] | None = None,1343        **kwargs: Any,1344    ) -> AsyncIterator[StreamEvent]: ...13451346    @overload1347    def astream_events(1348        self,1349        input: Any,1350        config: RunnableConfig | None = None,1351        *,1352        version: Literal["v3"],1353        **kwargs: Any,1354    ) -> Awaitable[Any]: ...13551356    def astream_events(1357        self,1358        input: Any,1359        config: RunnableConfig | None = None,1360        *,1361        version: Literal["v1", "v2", "v3"] = "v2",1362        include_names: Sequence[str] | None = None,1363        include_types: Sequence[str] | None = None,1364        include_tags: Sequence[str] | None = None,1365        exclude_names: Sequence[str] | None = None,1366        exclude_types: Sequence[str] | None = None,1367        exclude_tags: Sequence[str] | None = None,1368        **kwargs: Any,1369    ) -> AsyncIterator[StreamEvent] | Awaitable[Any]:1370        """Generate a stream of events.13711372        Use to create an iterator over `StreamEvent` that provide real-time information1373        about the progress of the `Runnable`, including `StreamEvent` from intermediate1374        results.13751376        A `StreamEvent` is a dictionary with the following schema:13771378        - `event`: Event names are of the format:1379            `on_[runnable_type]_(start|stream|end)`.1380        - `name`: The name of the `Runnable` that generated the event.1381        - `run_id`: Randomly generated ID associated with the given execution of the1382            `Runnable` that emitted the event. A child `Runnable` that gets invoked as1383            part of the execution of a parent `Runnable` is assigned its own unique ID.1384        - `parent_ids`: The IDs of the parent runnables that generated the event. The1385            root `Runnable` will have an empty list. The order of the parent IDs is from1386            the root to the immediate parent. Only available for v2 version of the API.1387            The v1 version of the API will return an empty list.1388        - `tags`: The tags of the `Runnable` that generated the event.1389        - `metadata`: The metadata of the `Runnable` that generated the event.1390        - `data`: The data associated with the event. The contents of this field1391            depend on the type of event. See the table below for more details.13921393        Below is a table that illustrates some events that might be emitted by various1394        chains. Metadata fields have been omitted from the table for brevity.1395        Chain definitions have been included after the table.13961397        !!! note1398            This reference table is for the v2 version of the schema.13991400        | event                  | name                 | chunk                               | input                                             | output                                              |1401        | ---------------------- | -------------------- | ----------------------------------- | ------------------------------------------------- | --------------------------------------------------- |1402        | `on_chat_model_start`  | `'[model name]'`     |                                     | `{"messages": [[SystemMessage, HumanMessage]]}`   |                                                     |1403        | `on_chat_model_stream` | `'[model name]'`     | `AIMessageChunk(content="hello")`   |                                                   |                                                     |1404        | `on_chat_model_end`    | `'[model name]'`     |                                     | `{"messages": [[SystemMessage, HumanMessage]]}`   | `AIMessageChunk(content="hello world")`             |1405        | `on_llm_start`         | `'[model name]'`     |                                     | `{'input': 'hello'}`                              |                                                     |1406        | `on_llm_stream`        | `'[model name]'`     | `'Hello' `                          |                                                   |                                                     |1407        | `on_llm_end`           | `'[model name]'`     |                                     | `'Hello human!'`                                  |                                                     |1408        | `on_chain_start`       | `'format_docs'`      |                                     |                                                   |                                                     |1409        | `on_chain_stream`      | `'format_docs'`      | `'hello world!, goodbye world!'`    |                                                   |                                                     |1410        | `on_chain_end`         | `'format_docs'`      |                                     | `[Document(...)]`                                 | `'hello world!, goodbye world!'`                    |1411        | `on_tool_start`        | `'some_tool'`        |                                     | `{"x": 1, "y": "2"}`                              |                                                     |1412        | `on_tool_end`          | `'some_tool'`        |                                     |                                                   | `{"x": 1, "y": "2"}`                                |1413        | `on_retriever_start`   | `'[retriever name]'` |                                     | `{"query": "hello"}`                              |                                                     |1414        | `on_retriever_end`     | `'[retriever name]'` |                                     | `{"query": "hello"}`                              | `[Document(...), ..]`                               |1415        | `on_prompt_start`      | `'[template_name]'`  |                                     | `{"question": "hello"}`                           |                                                     |1416        | `on_prompt_end`        | `'[template_name]'`  |                                     | `{"question": "hello"}`                           | `ChatPromptValue(messages: [SystemMessage, ...])`   |14171418        In addition to the standard events, users can also dispatch custom events (see example below).14191420        Custom events will be only be surfaced with in the v2 version of the API!14211422        A custom event has following format:14231424        | Attribute   | Type   | Description                                                                                               |1425        | ----------- | ------ | --------------------------------------------------------------------------------------------------------- |1426        | `name`      | `str`  | A user defined name for the event.                                                                        |1427        | `data`      | `Any`  | The data associated with the event. This can be anything, though we suggest making it JSON serializable.  |14281429        Here are declarations associated with the standard events shown above:14301431        `format_docs`:14321433        ```python1434        def format_docs(docs: list[Document]) -> str:1435            '''Format the docs.'''1436            return ", ".join([doc.page_content for doc in docs])143714381439        format_docs = RunnableLambda(format_docs)1440        ```14411442        `some_tool`:14431444        ```python1445        @tool1446        def some_tool(x: int, y: str) -> dict:1447            '''Some_tool.'''1448            return {"x": x, "y": y}1449        ```14501451        `prompt`:14521453        ```python1454        template = ChatPromptTemplate.from_messages(1455            [1456                ("system", "You are Cat Agent 007"),1457                ("human", "{question}"),1458            ]1459        ).with_config({"run_name": "my_template", "tags": ["my_template"]})1460        ```14611462        !!! example14631464            ```python1465            from langchain_core.runnables import RunnableLambda146614671468            async def reverse(s: str) -> str:1469                return s[::-1]147014711472            chain = RunnableLambda(func=reverse)14731474            events = [1475                event async for event in chain.astream_events("hello", version="v2")1476            ]14771478            # Will produce the following events1479            # (run_id, and parent_ids has been omitted for brevity):1480            [1481                {1482                    "data": {"input": "hello"},1483                    "event": "on_chain_start",1484                    "metadata": {},1485                    "name": "reverse",1486                    "tags": [],1487                },1488                {1489                    "data": {"chunk": "olleh"},1490                    "event": "on_chain_stream",1491                    "metadata": {},1492                    "name": "reverse",1493                    "tags": [],1494                },1495                {1496                    "data": {"output": "olleh"},1497                    "event": "on_chain_end",1498                    "metadata": {},1499                    "name": "reverse",1500                    "tags": [],1501                },1502            ]1503            ```15041505        ```python title="Dispatch custom event"1506        from langchain_core.callbacks.manager import (1507            adispatch_custom_event,1508        )1509        from langchain_core.runnables import RunnableLambda, RunnableConfig1510        import asyncio151115121513        async def slow_thing(some_input: str, config: RunnableConfig) -> str:1514            \"\"\"Do something that takes a long time.\"\"\"1515            await asyncio.sleep(1) # Placeholder for some slow operation1516            await adispatch_custom_event(1517                "progress_event",1518                {"message": "Finished step 1 of 3"},1519                config=config # Must be included for python < 3.101520            )1521            await asyncio.sleep(1) # Placeholder for some slow operation1522            await adispatch_custom_event(1523                "progress_event",1524                {"message": "Finished step 2 of 3"},1525                config=config # Must be included for python < 3.101526            )1527            await asyncio.sleep(1) # Placeholder for some slow operation1528            return "Done"15291530        slow_thing = RunnableLambda(slow_thing)15311532        async for event in slow_thing.astream_events("some_input", version="v2"):1533            print(event)1534        ```15351536        Args:1537            input: The input to the `Runnable`.1538            config: The config to use for the `Runnable`.1539            version: The version of the schema to use. One of `'v1'`, `'v2'`,1540                or `'v3'`.15411542                Most callers should use `'v2'` (the default), which yields1543                `StreamEvent` dicts and supports custom events.15441545                `'v3'` selects the typed, content-block-centric streaming1546                protocol and is only supported on `Runnable` subclasses that1547                implement it (currently `BaseChatModel` and1548                `langgraph.CompiledGraph`); on a generic `Runnable` it raises1549                `NotImplementedError`. The `'v3'` API is in beta and may1550                change. See the subclass override (e.g.1551                `BaseChatModel.astream_events`) for the v3 return shape.15521553                `'v1'` is retained for backwards compatibility and will be1554                deprecated in `0.4.0`. Custom events are only surfaced in1555                `'v2'` / `'v3'`.1556            include_names: Only include events from `Runnable` objects with matching names.1557            include_types: Only include events from `Runnable` objects with matching types.1558            include_tags: Only include events from `Runnable` objects with matching tags.1559            exclude_names: Exclude events from `Runnable` objects with matching names.1560            exclude_types: Exclude events from `Runnable` objects with matching types.1561            exclude_tags: Exclude events from `Runnable` objects with matching tags.1562            **kwargs: Additional keyword arguments to pass to the `Runnable`.15631564        Yields:1565            An async stream of `StreamEvent`.15661567        Raises:1568            NotImplementedError: If the version is not `'v1'`, `'v2'`, or `'v3'`, or1569                if `'v3'` is requested on a `Runnable` that does not implement the v31570                streaming protocol.15711572        """  # noqa: E5011573        if version == "v3":1574            return self._astream_events_v3_unsupported()1575        return self._astream_events_v1_v2(1576            input,1577            config=config,1578            version=version,1579            include_names=include_names,1580            include_types=include_types,1581            include_tags=include_tags,1582            exclude_names=exclude_names,1583            exclude_types=exclude_types,1584            exclude_tags=exclude_tags,1585            **kwargs,1586        )15871588    async def _astream_events_v3_unsupported(self) -> Any:1589        """Coroutine that raises when v3 isn't implemented on this Runnable.15901591        Lets the public `astream_events(version="v3")` return an awaitable1592        whose error surfaces on `await`, matching the v3 contract on1593        subclasses that do implement the protocol.1594        """1595        msg = (1596            "astream_events(version='v3') is only supported on Runnable "1597            "subclasses that implement the v3 streaming protocol "1598            "(BaseChatModel, CompiledGraph). "1599            f"Got: {type(self).__name__}"1600        )1601        raise NotImplementedError(msg)16021603    async def _astream_events_v1_v2(1604        self,1605        input: Any,1606        config: RunnableConfig | None = None,1607        *,1608        version: Literal["v1", "v2"] = "v2",1609        include_names: Sequence[str] | None = None,1610        include_types: Sequence[str] | None = None,1611        include_tags: Sequence[str] | None = None,1612        exclude_names: Sequence[str] | None = None,1613        exclude_types: Sequence[str] | None = None,1614        exclude_tags: Sequence[str] | None = None,1615        **kwargs: Any,1616    ) -> AsyncIterator[StreamEvent]:1617        if version == "v2":1618            event_stream = _astream_events_implementation_v2(1619                self,1620                input,1621                config=config,1622                include_names=include_names,1623                include_types=include_types,1624                include_tags=include_tags,1625                exclude_names=exclude_names,1626                exclude_types=exclude_types,1627                exclude_tags=exclude_tags,1628                **kwargs,1629            )1630        elif version == "v1":1631            warn_deprecated(1632                since="1.3.3",1633                message=(1634                    "astream_events version='v1' is deprecated. "1635                    "Use version='v2' or astream instead."1636                ),1637                removal="2.0.0",1638            )1639            # First implementation, built on top of astream_log API1640            # This implementation will be deprecated as of 0.2.01641            event_stream = _astream_events_implementation_v1(1642                self,1643                input,1644                config=config,1645                include_names=include_names,1646                include_types=include_types,1647                include_tags=include_tags,1648                exclude_names=exclude_names,1649                exclude_types=exclude_types,1650                exclude_tags=exclude_tags,1651                **kwargs,1652            )1653        else:1654            msg = f"Unsupported version: {version!r}. Expected 'v1', 'v2', or 'v3'."1655            raise NotImplementedError(msg)16561657        async with aclosing(event_stream):1658            async for event in event_stream:1659                yield event16601661    @overload1662    def stream_events(1663        self,1664        input: Any,1665        config: RunnableConfig | None = None,1666        *,1667        version: Literal["v1", "v2"] = "v2",1668        include_names: Sequence[str] | None = None,1669        include_types: Sequence[str] | None = None,1670        include_tags: Sequence[str] | None = None,1671        exclude_names: Sequence[str] | None = None,1672        exclude_types: Sequence[str] | None = None,1673        exclude_tags: Sequence[str] | None = None,1674        **kwargs: Any,1675    ) -> Iterator[StreamEvent]: ...16761677    @overload1678    def stream_events(1679        self,1680        input: Any,1681        config: RunnableConfig | None = None,1682        *,1683        version: Literal["v3"],1684        **kwargs: Any,1685    ) -> Iterator[Any]: ...16861687    def stream_events(1688        self,1689        input: Any,1690        config: RunnableConfig | None = None,1691        *,1692        version: Literal["v1", "v2", "v3"] = "v2",1693        include_names: Sequence[str] | None = None,1694        include_types: Sequence[str] | None = None,1695        include_tags: Sequence[str] | None = None,1696        exclude_names: Sequence[str] | None = None,1697        exclude_types: Sequence[str] | None = None,1698        exclude_tags: Sequence[str] | None = None,1699        **kwargs: Any,1700    ) -> Iterator[StreamEvent] | Iterator[Any]:1701        """Generate a stream of events synchronously.17021703        Synchronous counterpart to `astream_events`. For `version='v3'`, subclasses1704        that implement the v3 streaming protocol (`BaseChatModel`, `CompiledGraph`)1705        override this method. All other versions and base-class calls raise1706        `NotImplementedError`.17071708        Args:1709            input: The input to the `Runnable`.1710            config: The config to use for the `Runnable`.1711            version: The version of the schema to use. `'v3'` requires a subclass1712                that implements the v3 streaming protocol. `'v1'` and `'v2'` are not1713                supported on the sync path.1714            include_names: Only include events from `Runnable` objects with matching1715                names.1716            include_types: Only include events from `Runnable` objects with matching1717                types.1718            include_tags: Only include events from `Runnable` objects with matching1719                tags.1720            exclude_names: Exclude events from `Runnable` objects with matching names.1721            exclude_types: Exclude events from `Runnable` objects with matching types.1722            exclude_tags: Exclude events from `Runnable` objects with matching tags.1723            **kwargs: Additional keyword arguments to pass to the `Runnable`.17241725        Raises:1726            NotImplementedError: Always. Subclasses override this method for supported1727                versions.17281729        """1730        # Base impl always raises; consume args so they don't trip ARG002.1731        del input, config, include_names, include_types, include_tags1732        del exclude_names, exclude_types, exclude_tags, kwargs1733        if version == "v3":1734            msg = (1735                "stream_events(version='v3') is only supported on Runnable subclasses "1736                "that implement the v3 streaming protocol "1737                "(BaseChatModel, CompiledGraph). "1738                f"Got: {type(self).__name__}"1739            )1740            raise NotImplementedError(msg)1741        msg = (1742            f"stream_events(version={version!r}) is not supported. "1743            "Use astream_events() for v1/v2, or stream_events(version='v3') "1744            "on a supported subclass."1745        )1746        raise NotImplementedError(msg)17471748    def transform(1749        self,1750        input: Iterator[Input],1751        config: RunnableConfig | None = None,1752        **kwargs: Any | None,1753    ) -> Iterator[Output]:1754        """Transform inputs to outputs.17551756        Default implementation of transform, which buffers input and calls `astream`.17571758        Subclasses must override this method if they can start producing output while1759        input is still being generated.17601761        Args:1762            input: An iterator of inputs to the `Runnable`.1763            config: The config to use for the `Runnable`.1764            **kwargs: Additional keyword arguments to pass to the `Runnable`.17651766        Yields:1767            The output of the `Runnable`.17681769        """1770        final: Input1771        got_first_val = False17721773        for ichunk in input:1774            # The default implementation of transform is to buffer input and1775            # then call stream.1776            # It'll attempt to gather all input into a single chunk using1777            # the `+` operator.1778            # If the input is not addable, then we'll assume that we can1779            # only operate on the last chunk,1780            # and we'll iterate until we get to the last chunk.1781            if not got_first_val:1782                final = ichunk1783                got_first_val = True1784            else:1785                try:1786                    final = final + ichunk  # type: ignore[operator]1787                except TypeError:1788                    final = ichunk17891790        if got_first_val:1791            yield from self.stream(final, config, **kwargs)17921793    async def atransform(1794        self,1795        input: AsyncIterator[Input],1796        config: RunnableConfig | None = None,1797        **kwargs: Any | None,1798    ) -> AsyncIterator[Output]:1799        """Transform inputs to outputs.18001801        Default implementation of atransform, which buffers input and calls `astream`.18021803        Subclasses must override this method if they can start producing output while1804        input is still being generated.18051806        Args:1807            input: An async iterator of inputs to the `Runnable`.1808            config: The config to use for the `Runnable`.1809            **kwargs: Additional keyword arguments to pass to the `Runnable`.18101811        Yields:1812            The output of the `Runnable`.18131814        """1815        final: Input1816        got_first_val = False18171818        async for ichunk in input:1819            # The default implementation of transform is to buffer input and1820            # then call stream.1821            # It'll attempt to gather all input into a single chunk using1822            # the `+` operator.1823            # If the input is not addable, then we'll assume that we can1824            # only operate on the last chunk,1825            # and we'll iterate until we get to the last chunk.1826            if not got_first_val:1827                final = ichunk1828                got_first_val = True1829            else:1830                try:1831                    final = final + ichunk  # type: ignore[operator]1832                except TypeError:1833                    final = ichunk18341835        if got_first_val:1836            async for output in self.astream(final, config, **kwargs):1837                yield output18381839    def bind(self, **kwargs: Any) -> Runnable[Input, Output]:1840        """Bind arguments to a `Runnable`, returning a new `Runnable`.18411842        Useful when a `Runnable` in a chain requires an argument that is not1843        in the output of the previous `Runnable` or included in the user input.18441845        Args:1846            **kwargs: The arguments to bind to the `Runnable`.18471848        Returns:1849            A new `Runnable` with the arguments bound.18501851        Example:1852            ```python1853            from langchain_ollama import ChatOllama1854            from langchain_core.output_parsers import StrOutputParser18551856            model = ChatOllama(model="llama3.1")18571858            # Without bind1859            chain = model | StrOutputParser()18601861            chain.invoke("Repeat quoted words exactly: 'One two three four five.'")1862            # Output is 'One two three four five.'18631864            # With bind1865            chain = model.bind(stop=["three"]) | StrOutputParser()18661867            chain.invoke("Repeat quoted words exactly: 'One two three four five.'")1868            # Output is 'One two'1869            ```1870        """1871        return RunnableBinding(bound=self, kwargs=kwargs, config={})18721873    def with_config(1874        self,1875        config: RunnableConfig | None = None,1876        # Sadly Unpack is not well-supported by mypy so this will have to be untyped1877        **kwargs: Any,1878    ) -> Runnable[Input, Output]:1879        """Bind config to a `Runnable`, returning a new `Runnable`.18801881        Args:1882            config: The config to bind to the `Runnable`.1883            **kwargs: Additional keyword arguments to pass to the `Runnable`.18841885        Returns:1886            A new `Runnable` with the config bound.18871888        """1889        return RunnableBinding(1890            bound=self,1891            config=cast(1892                "RunnableConfig",1893                {**(config or {}), **kwargs},1894            ),1895            kwargs={},1896        )18971898    def with_listeners(1899        self,1900        *,1901        on_start: Callable[[Run], None]1902        | Callable[[Run, RunnableConfig], None]1903        | None = None,1904        on_end: Callable[[Run], None]1905        | Callable[[Run, RunnableConfig], None]1906        | None = None,1907        on_error: Callable[[Run], None]1908        | Callable[[Run, RunnableConfig], None]1909        | None = None,1910    ) -> Runnable[Input, Output]:1911        """Bind lifecycle listeners to a `Runnable`, returning a new `Runnable`.19121913        The Run object contains information about the run, including its `id`,1914        `type`, `input`, `output`, `error`, `start_time`, `end_time`, and1915        any tags or metadata added to the run.19161917        Args:1918            on_start: Called before the `Runnable` starts running, with the `Run`1919                object.1920            on_end: Called after the `Runnable` finishes running, with the `Run`1921                object.1922            on_error: Called if the `Runnable` throws an error, with the `Run`1923                object.19241925        Returns:1926            A new `Runnable` with the listeners bound.19271928        Example:1929            ```python1930            from langchain_core.runnables import RunnableLambda1931            from langchain_core.tracers.schemas import Run19321933            import time193419351936            def test_runnable(time_to_sleep: int):1937                time.sleep(time_to_sleep)193819391940            def fn_start(run_obj: Run):1941                print("start_time:", run_obj.start_time)194219431944            def fn_end(run_obj: Run):1945                print("end_time:", run_obj.end_time)194619471948            chain = RunnableLambda(test_runnable).with_listeners(1949                on_start=fn_start, on_end=fn_end1950            )1951            chain.invoke(2)1952            ```1953        """1954        return RunnableBinding(1955            bound=self,1956            config_factories=[1957                lambda config: {1958                    "callbacks": [1959                        RootListenersTracer(1960                            config=config,1961                            on_start=on_start,1962                            on_end=on_end,1963                            on_error=on_error,1964                        )1965                    ],1966                }1967            ],1968        )19691970    def with_alisteners(1971        self,1972        *,1973        on_start: AsyncListener | None = None,1974        on_end: AsyncListener | None = None,1975        on_error: AsyncListener | None = None,1976    ) -> Runnable[Input, Output]:1977        """Bind async lifecycle listeners to a `Runnable`.19781979        Returns a new `Runnable`.19801981        The Run object contains information about the run, including its `id`,1982        `type`, `input`, `output`, `error`, `start_time`, `end_time`, and1983        any tags or metadata added to the run.19841985        Args:1986            on_start: Called asynchronously before the `Runnable` starts running,1987                with the `Run` object.1988            on_end: Called asynchronously after the `Runnable` finishes running,1989                with the `Run` object.1990            on_error: Called asynchronously if the `Runnable` throws an error,1991                with the `Run` object.19921993        Returns:1994            A new `Runnable` with the listeners bound.19951996        Example:1997            ```python1998            from langchain_core.runnables import RunnableLambda, Runnable1999            from datetime import datetime, timezone2000            import time

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.