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.