langchain-core 0.3.74__py3-none-any.whl → 0.3.76__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of langchain-core might be problematic. Click here for more details.

Files changed (122) hide show
  1. langchain_core/_api/beta_decorator.py +18 -41
  2. langchain_core/_api/deprecation.py +20 -7
  3. langchain_core/_api/path.py +19 -2
  4. langchain_core/_import_utils.py +7 -0
  5. langchain_core/agents.py +10 -6
  6. langchain_core/beta/runnables/context.py +2 -3
  7. langchain_core/callbacks/base.py +11 -4
  8. langchain_core/callbacks/file.py +13 -2
  9. langchain_core/callbacks/manager.py +129 -78
  10. langchain_core/callbacks/usage.py +4 -2
  11. langchain_core/chat_history.py +10 -12
  12. langchain_core/document_loaders/base.py +34 -9
  13. langchain_core/document_loaders/langsmith.py +3 -0
  14. langchain_core/documents/base.py +36 -11
  15. langchain_core/documents/compressor.py +9 -6
  16. langchain_core/documents/transformers.py +4 -2
  17. langchain_core/embeddings/fake.py +8 -5
  18. langchain_core/env.py +2 -3
  19. langchain_core/example_selectors/base.py +12 -0
  20. langchain_core/exceptions.py +7 -0
  21. langchain_core/globals.py +17 -28
  22. langchain_core/indexing/api.py +56 -44
  23. langchain_core/indexing/base.py +7 -10
  24. langchain_core/indexing/in_memory.py +23 -3
  25. langchain_core/language_models/__init__.py +3 -2
  26. langchain_core/language_models/base.py +64 -39
  27. langchain_core/language_models/chat_models.py +130 -42
  28. langchain_core/language_models/fake_chat_models.py +10 -11
  29. langchain_core/language_models/llms.py +49 -17
  30. langchain_core/load/dump.py +5 -7
  31. langchain_core/load/load.py +15 -1
  32. langchain_core/load/serializable.py +38 -43
  33. langchain_core/memory.py +7 -3
  34. langchain_core/messages/ai.py +36 -16
  35. langchain_core/messages/base.py +13 -6
  36. langchain_core/messages/content_blocks.py +23 -2
  37. langchain_core/messages/human.py +2 -6
  38. langchain_core/messages/modifier.py +1 -1
  39. langchain_core/messages/system.py +2 -6
  40. langchain_core/messages/tool.py +36 -16
  41. langchain_core/messages/utils.py +198 -87
  42. langchain_core/output_parsers/base.py +5 -2
  43. langchain_core/output_parsers/json.py +4 -4
  44. langchain_core/output_parsers/list.py +7 -22
  45. langchain_core/output_parsers/openai_functions.py +3 -0
  46. langchain_core/output_parsers/openai_tools.py +8 -1
  47. langchain_core/output_parsers/pydantic.py +4 -0
  48. langchain_core/output_parsers/string.py +5 -1
  49. langchain_core/output_parsers/transform.py +2 -2
  50. langchain_core/output_parsers/xml.py +23 -22
  51. langchain_core/outputs/chat_generation.py +18 -7
  52. langchain_core/outputs/generation.py +14 -3
  53. langchain_core/outputs/llm_result.py +8 -1
  54. langchain_core/prompt_values.py +10 -4
  55. langchain_core/prompts/base.py +4 -9
  56. langchain_core/prompts/chat.py +88 -61
  57. langchain_core/prompts/dict.py +16 -8
  58. langchain_core/prompts/few_shot.py +9 -11
  59. langchain_core/prompts/few_shot_with_templates.py +5 -1
  60. langchain_core/prompts/image.py +12 -5
  61. langchain_core/prompts/message.py +5 -6
  62. langchain_core/prompts/pipeline.py +13 -8
  63. langchain_core/prompts/prompt.py +22 -8
  64. langchain_core/prompts/string.py +18 -10
  65. langchain_core/prompts/structured.py +7 -2
  66. langchain_core/rate_limiters.py +2 -2
  67. langchain_core/retrievers.py +7 -6
  68. langchain_core/runnables/base.py +842 -567
  69. langchain_core/runnables/branch.py +15 -20
  70. langchain_core/runnables/config.py +11 -17
  71. langchain_core/runnables/configurable.py +34 -19
  72. langchain_core/runnables/fallbacks.py +24 -17
  73. langchain_core/runnables/graph.py +47 -40
  74. langchain_core/runnables/graph_ascii.py +40 -17
  75. langchain_core/runnables/graph_mermaid.py +27 -15
  76. langchain_core/runnables/graph_png.py +27 -31
  77. langchain_core/runnables/history.py +56 -59
  78. langchain_core/runnables/passthrough.py +47 -24
  79. langchain_core/runnables/retry.py +10 -6
  80. langchain_core/runnables/router.py +10 -9
  81. langchain_core/runnables/schema.py +2 -0
  82. langchain_core/runnables/utils.py +51 -89
  83. langchain_core/stores.py +13 -25
  84. langchain_core/structured_query.py +3 -7
  85. langchain_core/sys_info.py +9 -8
  86. langchain_core/tools/base.py +30 -23
  87. langchain_core/tools/convert.py +24 -13
  88. langchain_core/tools/simple.py +35 -3
  89. langchain_core/tools/structured.py +26 -3
  90. langchain_core/tracers/_streaming.py +6 -7
  91. langchain_core/tracers/base.py +2 -2
  92. langchain_core/tracers/context.py +5 -1
  93. langchain_core/tracers/core.py +109 -39
  94. langchain_core/tracers/evaluation.py +22 -26
  95. langchain_core/tracers/event_stream.py +41 -28
  96. langchain_core/tracers/langchain.py +12 -3
  97. langchain_core/tracers/langchain_v1.py +10 -2
  98. langchain_core/tracers/log_stream.py +57 -18
  99. langchain_core/tracers/root_listeners.py +4 -20
  100. langchain_core/tracers/run_collector.py +6 -16
  101. langchain_core/tracers/schemas.py +5 -1
  102. langchain_core/utils/aiter.py +14 -6
  103. langchain_core/utils/env.py +3 -0
  104. langchain_core/utils/function_calling.py +49 -30
  105. langchain_core/utils/interactive_env.py +6 -2
  106. langchain_core/utils/iter.py +11 -3
  107. langchain_core/utils/json.py +5 -2
  108. langchain_core/utils/json_schema.py +15 -5
  109. langchain_core/utils/loading.py +5 -1
  110. langchain_core/utils/mustache.py +24 -15
  111. langchain_core/utils/pydantic.py +32 -4
  112. langchain_core/utils/utils.py +24 -8
  113. langchain_core/vectorstores/base.py +7 -20
  114. langchain_core/vectorstores/in_memory.py +18 -12
  115. langchain_core/vectorstores/utils.py +18 -12
  116. langchain_core/version.py +1 -1
  117. langchain_core-0.3.76.dist-info/METADATA +77 -0
  118. langchain_core-0.3.76.dist-info/RECORD +174 -0
  119. langchain_core-0.3.74.dist-info/METADATA +0 -108
  120. langchain_core-0.3.74.dist-info/RECORD +0 -174
  121. {langchain_core-0.3.74.dist-info → langchain_core-0.3.76.dist-info}/WHEEL +0 -0
  122. {langchain_core-0.3.74.dist-info → langchain_core-0.3.76.dist-info}/entry_points.txt +0 -0
@@ -12,6 +12,10 @@ from typing import (
12
12
  from pydantic import BaseModel, ConfigDict
13
13
  from typing_extensions import override
14
14
 
15
+ from langchain_core.beta.runnables.context import (
16
+ CONTEXT_CONFIG_PREFIX,
17
+ CONTEXT_CONFIG_SUFFIX_SET,
18
+ )
15
19
  from langchain_core.runnables.base import (
16
20
  Runnable,
17
21
  RunnableLike,
@@ -44,10 +48,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
44
48
 
45
49
  If no condition evaluates to True, the default branch is run on the input.
46
50
 
47
- Parameters:
48
- branches: A list of (condition, Runnable) pairs.
49
- default: A Runnable to run if no condition is met.
50
-
51
51
  Examples:
52
52
 
53
53
  .. code-block:: python
@@ -61,13 +61,15 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
61
61
  lambda x: "goodbye",
62
62
  )
63
63
 
64
- branch.invoke("hello") # "HELLO"
65
- branch.invoke(None) # "goodbye"
64
+ branch.invoke("hello") # "HELLO"
65
+ branch.invoke(None) # "goodbye"
66
66
 
67
67
  """
68
68
 
69
69
  branches: Sequence[tuple[Runnable[Input, bool], Runnable[Input, Output]]]
70
+ """A list of (condition, Runnable) pairs."""
70
71
  default: Runnable[Input, Output]
72
+ """A Runnable to run if no condition is met."""
71
73
 
72
74
  def __init__(
73
75
  self,
@@ -136,7 +138,7 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
136
138
  super().__init__(
137
139
  branches=branches_,
138
140
  default=default_,
139
- ) # type: ignore[call-arg]
141
+ )
140
142
 
141
143
  model_config = ConfigDict(
142
144
  arbitrary_types_allowed=True,
@@ -144,12 +146,17 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
144
146
 
145
147
  @classmethod
146
148
  def is_lc_serializable(cls) -> bool:
147
- """RunnableBranch is serializable if all its branches are serializable."""
149
+ """Return True as this class is serializable."""
148
150
  return True
149
151
 
150
152
  @classmethod
151
153
  @override
152
154
  def get_lc_namespace(cls) -> list[str]:
155
+ """Get the namespace of the langchain object.
156
+
157
+ Returns:
158
+ ``["langchain", "schema", "runnable"]``
159
+ """
153
160
  return ["langchain", "schema", "runnable"]
154
161
 
155
162
  @override
@@ -174,11 +181,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
174
181
  @property
175
182
  @override
176
183
  def config_specs(self) -> list[ConfigurableFieldSpec]:
177
- from langchain_core.beta.runnables.context import (
178
- CONTEXT_CONFIG_PREFIX,
179
- CONTEXT_CONFIG_SUFFIX_SET,
180
- )
181
-
182
184
  specs = get_unique_config_specs(
183
185
  spec
184
186
  for step in (
@@ -260,7 +262,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
260
262
  async def ainvoke(
261
263
  self, input: Input, config: Optional[RunnableConfig] = None, **kwargs: Any
262
264
  ) -> Output:
263
- """Async version of invoke."""
264
265
  config = ensure_config(config)
265
266
  callback_manager = get_async_callback_manager_for_config(config)
266
267
  run_manager = await callback_manager.on_chain_start(
@@ -321,9 +322,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
321
322
 
322
323
  Yields:
323
324
  The output of the branch that was run.
324
-
325
- Raises:
326
- BaseException: If an error occurs during the execution of the Runnable.
327
325
  """
328
326
  config = ensure_config(config)
329
327
  callback_manager = get_callback_manager_for_config(config)
@@ -408,9 +406,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
408
406
 
409
407
  Yields:
410
408
  The output of the branch that was run.
411
-
412
- Raises:
413
- BaseException: If an error occurs during the execution of the Runnable.
414
409
  """
415
410
  config = ensure_config(config)
416
411
  callback_manager = get_async_callback_manager_for_config(config)
@@ -12,21 +12,22 @@ from contextvars import Context, ContextVar, Token, copy_context
12
12
  from functools import partial
13
13
  from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, cast
14
14
 
15
+ from langsmith.run_helpers import _set_tracing_context, get_tracing_context
15
16
  from typing_extensions import ParamSpec, TypedDict
16
17
 
18
+ from langchain_core.callbacks.manager import AsyncCallbackManager, CallbackManager
17
19
  from langchain_core.runnables.utils import (
18
20
  Input,
19
21
  Output,
20
22
  accepts_config,
21
23
  accepts_run_manager,
22
24
  )
25
+ from langchain_core.tracers.langchain import LangChainTracer
23
26
 
24
27
  if TYPE_CHECKING:
25
28
  from langchain_core.callbacks.base import BaseCallbackManager, Callbacks
26
29
  from langchain_core.callbacks.manager import (
27
- AsyncCallbackManager,
28
30
  AsyncCallbackManagerForChainRun,
29
- CallbackManager,
30
31
  CallbackManagerForChainRun,
31
32
  )
32
33
  else:
@@ -125,9 +126,10 @@ def _set_config_context(
125
126
 
126
127
  Args:
127
128
  config (RunnableConfig): The config to set.
128
- """
129
- from langchain_core.tracers.langchain import LangChainTracer
130
129
 
130
+ Returns:
131
+ The token to reset the config and the previous tracing context.
132
+ """
131
133
  config_token = var_child_runnable_config.set(config)
132
134
  current_context = None
133
135
  if (
@@ -147,8 +149,6 @@ def _set_config_context(
147
149
  )
148
150
  and (run := tracer.run_map.get(str(parent_run_id)))
149
151
  ):
150
- from langsmith.run_helpers import _set_tracing_context, get_tracing_context
151
-
152
152
  current_context = get_tracing_context()
153
153
  _set_tracing_context({"parent": run})
154
154
  return config_token, current_context
@@ -160,9 +160,10 @@ def set_config_context(config: RunnableConfig) -> Generator[Context, None, None]
160
160
 
161
161
  Args:
162
162
  config (RunnableConfig): The config to set.
163
- """
164
- from langsmith.run_helpers import _set_tracing_context
165
163
 
164
+ Yields:
165
+ The config context.
166
+ """
166
167
  ctx = copy_context()
167
168
  config_token, _ = ctx.run(_set_config_context, config)
168
169
  try:
@@ -402,7 +403,7 @@ def call_func_with_variable_args(
402
403
  Callable[[Input, CallbackManagerForChainRun], Output],
403
404
  Callable[[Input, CallbackManagerForChainRun, RunnableConfig], Output],
404
405
  ],
405
- input: Input, # noqa: A002
406
+ input: Input,
406
407
  config: RunnableConfig,
407
408
  run_manager: Optional[CallbackManagerForChainRun] = None,
408
409
  **kwargs: Any,
@@ -439,7 +440,7 @@ def acall_func_with_variable_args(
439
440
  Awaitable[Output],
440
441
  ],
441
442
  ],
442
- input: Input, # noqa: A002
443
+ input: Input,
443
444
  config: RunnableConfig,
444
445
  run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
445
446
  **kwargs: Any,
@@ -475,8 +476,6 @@ def get_callback_manager_for_config(config: RunnableConfig) -> CallbackManager:
475
476
  Returns:
476
477
  CallbackManager: The callback manager.
477
478
  """
478
- from langchain_core.callbacks.manager import CallbackManager
479
-
480
479
  return CallbackManager.configure(
481
480
  inheritable_callbacks=config.get("callbacks"),
482
481
  inheritable_tags=config.get("tags"),
@@ -495,8 +494,6 @@ def get_async_callback_manager_for_config(
495
494
  Returns:
496
495
  AsyncCallbackManager: The async callback manager.
497
496
  """
498
- from langchain_core.callbacks.manager import AsyncCallbackManager
499
-
500
497
  return AsyncCallbackManager.configure(
501
498
  inheritable_callbacks=config.get("callbacks"),
502
499
  inheritable_tags=config.get("tags"),
@@ -598,9 +595,6 @@ async def run_in_executor(
598
595
 
599
596
  Returns:
600
597
  Output: The output of the function.
601
-
602
- Raises:
603
- RuntimeError: If the function raises a StopIteration.
604
598
  """
605
599
 
606
600
  def wrapper() -> T:
@@ -51,17 +51,15 @@ if TYPE_CHECKING:
51
51
  class DynamicRunnable(RunnableSerializable[Input, Output]):
52
52
  """Serializable Runnable that can be dynamically configured.
53
53
 
54
- A DynamicRunnable should be initiated using the `configurable_fields` or
55
- `configurable_alternatives` method of a Runnable.
56
-
57
- Parameters:
58
- default: The default Runnable to use.
59
- config: The configuration to use.
54
+ A DynamicRunnable should be initiated using the ``configurable_fields`` or
55
+ ``configurable_alternatives`` method of a Runnable.
60
56
  """
61
57
 
62
58
  default: RunnableSerializable[Input, Output]
59
+ """The default Runnable to use."""
63
60
 
64
61
  config: Optional[RunnableConfig] = None
62
+ """The configuration to use."""
65
63
 
66
64
  model_config = ConfigDict(
67
65
  arbitrary_types_allowed=True,
@@ -70,11 +68,17 @@ class DynamicRunnable(RunnableSerializable[Input, Output]):
70
68
  @classmethod
71
69
  @override
72
70
  def is_lc_serializable(cls) -> bool:
71
+ """Return True as this class is serializable."""
73
72
  return True
74
73
 
75
74
  @classmethod
76
75
  @override
77
76
  def get_lc_namespace(cls) -> list[str]:
77
+ """Get the namespace of the langchain object.
78
+
79
+ Returns:
80
+ ``["langchain", "schema", "runnable"]``
81
+ """
78
82
  return ["langchain", "schema", "runnable"]
79
83
 
80
84
  @property
@@ -322,9 +326,6 @@ class RunnableConfigurableFields(DynamicRunnable[Input, Output]):
322
326
  A RunnableConfigurableFields should be initiated using the
323
327
  `configurable_fields` method of a Runnable.
324
328
 
325
- Parameters:
326
- fields: The configurable fields to use.
327
-
328
329
  Here is an example of using a RunnableConfigurableFields with LLMs:
329
330
 
330
331
  .. code-block:: python
@@ -382,6 +383,7 @@ class RunnableConfigurableFields(DynamicRunnable[Input, Output]):
382
383
  """
383
384
 
384
385
  fields: dict[str, AnyConfigurableField]
386
+ """The configurable fields to use."""
385
387
 
386
388
  @property
387
389
  def config_specs(self) -> list[ConfigurableFieldSpec]:
@@ -501,7 +503,7 @@ class RunnableConfigurableAlternatives(DynamicRunnable[Input, Output]):
501
503
  ).configurable_alternatives(
502
504
  ConfigurableField(id="prompt"),
503
505
  default_key="joke",
504
- poem=PromptTemplate.from_template("Write a short poem about {topic}")
506
+ poem=PromptTemplate.from_template("Write a short poem about {topic}"),
505
507
  )
506
508
 
507
509
  # When invoking the created RunnableSequence, you can pass in the
@@ -511,7 +513,9 @@ class RunnableConfigurableAlternatives(DynamicRunnable[Input, Output]):
511
513
 
512
514
  # The `with_config` method brings in the desired Prompt Runnable in your
513
515
  # Runnable Sequence.
514
- chain.with_config(configurable={"prompt": "poem"}).invoke({"topic": "bears"})
516
+ chain.with_config(configurable={"prompt": "poem"}).invoke(
517
+ {"topic": "bears"}
518
+ )
515
519
 
516
520
 
517
521
  Equivalently, you can initialize RunnableConfigurableAlternatives directly
@@ -520,20 +524,28 @@ class RunnableConfigurableAlternatives(DynamicRunnable[Input, Output]):
520
524
  .. code-block:: python
521
525
 
522
526
  from langchain_core.runnables import ConfigurableField
523
- from langchain_core.runnables.configurable import RunnableConfigurableAlternatives
527
+ from langchain_core.runnables.configurable import (
528
+ RunnableConfigurableAlternatives,
529
+ )
524
530
  from langchain_openai import ChatOpenAI
525
531
 
526
532
  prompt = RunnableConfigurableAlternatives(
527
- which=ConfigurableField(id='prompt'),
533
+ which=ConfigurableField(id="prompt"),
528
534
  default=PromptTemplate.from_template("Tell me a joke about {topic}"),
529
- default_key='joke',
535
+ default_key="joke",
530
536
  prefix_keys=False,
531
- alternatives={"poem":PromptTemplate.from_template("Write a short poem about {topic}")}
537
+ alternatives={
538
+ "poem": PromptTemplate.from_template(
539
+ "Write a short poem about {topic}"
540
+ )
541
+ },
532
542
  )
533
543
  chain = prompt | ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
534
- chain.with_config(configurable={"prompt": "poem"}).invoke({"topic": "bears"})
544
+ chain.with_config(configurable={"prompt": "poem"}).invoke(
545
+ {"topic": "bears"}
546
+ )
535
547
 
536
- """ # noqa: E501
548
+ """
537
549
 
538
550
  which: ConfigurableField
539
551
  """The ConfigurableField to use to choose between alternatives."""
@@ -680,7 +692,10 @@ def make_options_spec(
680
692
  spec: Union[ConfigurableFieldSingleOption, ConfigurableFieldMultiOption],
681
693
  description: Optional[str],
682
694
  ) -> ConfigurableFieldSpec:
683
- """Make a ConfigurableFieldSpec for a ConfigurableFieldSingleOption or ConfigurableFieldMultiOption.
695
+ """Make options spec.
696
+
697
+ Make a ConfigurableFieldSpec for a ConfigurableFieldSingleOption or
698
+ ConfigurableFieldMultiOption.
684
699
 
685
700
  Args:
686
701
  spec: The ConfigurableFieldSingleOption or ConfigurableFieldMultiOption.
@@ -688,7 +703,7 @@ def make_options_spec(
688
703
 
689
704
  Returns:
690
705
  The ConfigurableFieldSpec.
691
- """ # noqa: E501
706
+ """
692
707
  with _enums_for_spec_lock:
693
708
  if enum := _enums_for_spec.get(spec):
694
709
  pass
@@ -5,11 +5,12 @@ import inspect
5
5
  import typing
6
6
  from collections.abc import AsyncIterator, Iterator, Sequence
7
7
  from functools import wraps
8
- from typing import TYPE_CHECKING, Any, Optional, Union
8
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
9
9
 
10
10
  from pydantic import BaseModel, ConfigDict
11
11
  from typing_extensions import override
12
12
 
13
+ from langchain_core.callbacks.manager import AsyncCallbackManager, CallbackManager
13
14
  from langchain_core.runnables.base import Runnable, RunnableSerializable
14
15
  from langchain_core.runnables.config import (
15
16
  RunnableConfig,
@@ -56,12 +57,12 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
56
57
  from langchain_core.chat_models.openai import ChatOpenAI
57
58
  from langchain_core.chat_models.anthropic import ChatAnthropic
58
59
 
59
- model = ChatAnthropic(
60
- model="claude-3-haiku-20240307"
61
- ).with_fallbacks([ChatOpenAI(model="gpt-3.5-turbo-0125")])
60
+ model = ChatAnthropic(model="claude-3-haiku-20240307").with_fallbacks(
61
+ [ChatOpenAI(model="gpt-3.5-turbo-0125")]
62
+ )
62
63
  # Will usually use ChatAnthropic, but fallback to ChatOpenAI
63
64
  # if ChatAnthropic fails.
64
- model.invoke('hello')
65
+ model.invoke("hello")
65
66
 
66
67
  # And you can also use fallbacks at the level of a chain.
67
68
  # Here if both LLM providers fail, we'll fallback to a good hardcoded
@@ -71,12 +72,16 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
71
72
  from langchain_core.output_parser import StrOutputParser
72
73
  from langchain_core.runnables import RunnableLambda
73
74
 
75
+
74
76
  def when_all_is_lost(inputs):
75
- return ("Looks like our LLM providers are down. "
76
- "Here's a nice 🦜️ emoji for you instead.")
77
+ return (
78
+ "Looks like our LLM providers are down. "
79
+ "Here's a nice 🦜️ emoji for you instead."
80
+ )
81
+
77
82
 
78
83
  chain_with_fallback = (
79
- PromptTemplate.from_template('Tell me a joke about {topic}')
84
+ PromptTemplate.from_template("Tell me a joke about {topic}")
80
85
  | model
81
86
  | StrOutputParser()
82
87
  ).with_fallbacks([RunnableLambda(when_all_is_lost)])
@@ -136,6 +141,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
136
141
  @classmethod
137
142
  @override
138
143
  def is_lc_serializable(cls) -> bool:
144
+ """Return True as this class is serializable."""
139
145
  return True
140
146
 
141
147
  @classmethod
@@ -143,13 +149,18 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
143
149
  def get_lc_namespace(cls) -> list[str]:
144
150
  """Get the namespace of the langchain object.
145
151
 
146
- Defaults to ["langchain", "schema", "runnable"].
152
+ Returns:
153
+ ``["langchain", "schema", "runnable"]``
147
154
  """
148
155
  return ["langchain", "schema", "runnable"]
149
156
 
150
157
  @property
151
158
  def runnables(self) -> Iterator[Runnable[Input, Output]]:
152
- """Iterator over the Runnable and its fallbacks."""
159
+ """Iterator over the Runnable and its fallbacks.
160
+
161
+ Yields:
162
+ The Runnable then its fallbacks.
163
+ """
153
164
  yield self.runnable
154
165
  yield from self.fallbacks
155
166
 
@@ -262,8 +273,6 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
262
273
  return_exceptions: bool = False,
263
274
  **kwargs: Optional[Any],
264
275
  ) -> list[Output]:
265
- from langchain_core.callbacks.manager import CallbackManager
266
-
267
276
  if self.exception_key is not None and not all(
268
277
  isinstance(input_, dict) for input_ in inputs
269
278
  ):
@@ -356,8 +365,6 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
356
365
  return_exceptions: bool = False,
357
366
  **kwargs: Optional[Any],
358
367
  ) -> list[Output]:
359
- from langchain_core.callbacks.manager import AsyncCallbackManager
360
-
361
368
  if self.exception_key is not None and not all(
362
369
  isinstance(input_, dict) for input_ in inputs
363
370
  ):
@@ -397,7 +404,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
397
404
  )
398
405
  )
399
406
 
400
- to_return = {}
407
+ to_return: dict[int, Union[Output, BaseException]] = {}
401
408
  run_again = dict(enumerate(inputs))
402
409
  handled_exceptions: dict[int, BaseException] = {}
403
410
  first_to_raise = None
@@ -447,7 +454,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
447
454
  if not return_exceptions and sorted_handled_exceptions:
448
455
  raise sorted_handled_exceptions[0][1]
449
456
  to_return.update(handled_exceptions)
450
- return [output for _, output in sorted(to_return.items())] # type: ignore[misc]
457
+ return [cast("Output", output) for _, output in sorted(to_return.items())]
451
458
 
452
459
  @override
453
460
  def stream(
@@ -569,7 +576,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
569
576
  async for chunk in stream:
570
577
  yield chunk
571
578
  try:
572
- output = output + chunk
579
+ output = output + chunk # type: ignore[operator]
573
580
  except TypeError:
574
581
  output = None
575
582
  except BaseException as e:
@@ -19,6 +19,8 @@ from typing import (
19
19
  )
20
20
  from uuid import UUID, uuid4
21
21
 
22
+ from langchain_core.load.serializable import to_json_not_implemented
23
+ from langchain_core.runnables.base import Runnable, RunnableSerializable
22
24
  from langchain_core.utils.pydantic import _IgnoreUnserializable, is_basemodel_subclass
23
25
 
24
26
  if TYPE_CHECKING:
@@ -62,19 +64,16 @@ def is_uuid(value: str) -> bool:
62
64
 
63
65
 
64
66
  class Edge(NamedTuple):
65
- """Edge in a graph.
66
-
67
- Parameters:
68
- source: The source node id.
69
- target: The target node id.
70
- data: Optional data associated with the edge. Defaults to None.
71
- conditional: Whether the edge is conditional. Defaults to False.
72
- """
67
+ """Edge in a graph."""
73
68
 
74
69
  source: str
70
+ """The source node id."""
75
71
  target: str
72
+ """The target node id."""
76
73
  data: Optional[Stringifiable] = None
74
+ """Optional data associated with the edge. Defaults to None."""
77
75
  conditional: bool = False
76
+ """Whether the edge is conditional. Defaults to False."""
78
77
 
79
78
  def copy(
80
79
  self, *, source: Optional[str] = None, target: Optional[str] = None
@@ -97,24 +96,21 @@ class Edge(NamedTuple):
97
96
 
98
97
 
99
98
  class Node(NamedTuple):
100
- """Node in a graph.
101
-
102
- Parameters:
103
- id: The unique identifier of the node.
104
- name: The name of the node.
105
- data: The data of the node.
106
- metadata: Optional metadata for the node. Defaults to None.
107
- """
99
+ """Node in a graph."""
108
100
 
109
101
  id: str
102
+ """The unique identifier of the node."""
110
103
  name: str
104
+ """The name of the node."""
111
105
  data: Union[type[BaseModel], RunnableType, None]
106
+ """The data of the node."""
112
107
  metadata: Optional[dict[str, Any]]
108
+ """Optional metadata for the node. Defaults to None."""
113
109
 
114
110
  def copy(
115
111
  self,
116
112
  *,
117
- id: Optional[str] = None, # noqa: A002
113
+ id: Optional[str] = None,
118
114
  name: Optional[str] = None,
119
115
  ) -> Node:
120
116
  """Return a copy of the node with optional new id and name.
@@ -135,16 +131,12 @@ class Node(NamedTuple):
135
131
 
136
132
 
137
133
  class Branch(NamedTuple):
138
- """Branch in a graph.
139
-
140
- Parameters:
141
- condition: A callable that returns a string representation of the condition.
142
- ends: Optional dictionary of end node ids for the branches. Defaults
143
- to None.
144
- """
134
+ """Branch in a graph."""
145
135
 
146
136
  condition: Callable[..., str]
137
+ """A callable that returns a string representation of the condition."""
147
138
  ends: Optional[dict[str, str]]
139
+ """Optional dictionary of end node ids for the branches. Defaults to None."""
148
140
 
149
141
 
150
142
  class CurveStyle(Enum):
@@ -168,7 +160,7 @@ class CurveStyle(Enum):
168
160
  class NodeStyles:
169
161
  """Schema for Hexadecimal color codes for different node types.
170
162
 
171
- Parameters:
163
+ Args:
172
164
  default: The default color code. Defaults to "fill:#f2f0ff,line-height:1.2".
173
165
  first: The color code for the first node. Defaults to "fill-opacity:0".
174
166
  last: The color code for the last node. Defaults to "fill:#bfb6fc".
@@ -182,12 +174,14 @@ class NodeStyles:
182
174
  class MermaidDrawMethod(Enum):
183
175
  """Enum for different draw methods supported by Mermaid."""
184
176
 
185
- PYPPETEER = "pyppeteer" # Uses Pyppeteer to render the graph
186
- API = "api" # Uses Mermaid.INK API to render the graph
177
+ PYPPETEER = "pyppeteer"
178
+ """Uses Pyppeteer to render the graph"""
179
+ API = "api"
180
+ """Uses Mermaid.INK API to render the graph"""
187
181
 
188
182
 
189
183
  def node_data_str(
190
- id: str, # noqa: A002
184
+ id: str,
191
185
  data: Union[type[BaseModel], RunnableType, None],
192
186
  ) -> str:
193
187
  """Convert the data of a node to a string.
@@ -199,8 +193,6 @@ def node_data_str(
199
193
  Returns:
200
194
  A string representation of the data.
201
195
  """
202
- from langchain_core.runnables.base import Runnable
203
-
204
196
  if not is_uuid(id) or data is None:
205
197
  return id
206
198
  data_str = data.get_name() if isinstance(data, Runnable) else data.__name__
@@ -220,9 +212,6 @@ def node_data_json(
220
212
  Returns:
221
213
  A dictionary with the type of the data and the data itself.
222
214
  """
223
- from langchain_core.load.serializable import to_json_not_implemented
224
- from langchain_core.runnables.base import Runnable, RunnableSerializable
225
-
226
215
  if node.data is None:
227
216
  json: dict[str, Any] = {}
228
217
  elif isinstance(node.data, RunnableSerializable):
@@ -269,7 +258,7 @@ def node_data_json(
269
258
  class Graph:
270
259
  """Graph of nodes and edges.
271
260
 
272
- Parameters:
261
+ Args:
273
262
  nodes: Dictionary of nodes in the graph. Defaults to an empty dictionary.
274
263
  edges: List of edges in the graph. Defaults to an empty list.
275
264
  """
@@ -328,7 +317,7 @@ class Graph:
328
317
  def add_node(
329
318
  self,
330
319
  data: Union[type[BaseModel], RunnableType, None],
331
- id: Optional[str] = None, # noqa: A002
320
+ id: Optional[str] = None,
332
321
  *,
333
322
  metadata: Optional[dict[str, Any]] = None,
334
323
  ) -> Node:
@@ -475,6 +464,10 @@ class Graph:
475
464
 
476
465
  If there is no such node, or there are multiple, return None.
477
466
  When drawing the graph, this node would be the origin.
467
+
468
+ Returns:
469
+ The first node, or None if there is no such node or multiple
470
+ candidates.
478
471
  """
479
472
  return _first_node(self)
480
473
 
@@ -483,6 +476,10 @@ class Graph:
483
476
 
484
477
  If there is no such node, or there are multiple, return None.
485
478
  When drawing the graph, this node would be the destination.
479
+
480
+ Returns:
481
+ The last node, or None if there is no such node or multiple
482
+ candidates.
486
483
  """
487
484
  return _last_node(self)
488
485
 
@@ -513,8 +510,13 @@ class Graph:
513
510
  self.remove_node(last_node)
514
511
 
515
512
  def draw_ascii(self) -> str:
516
- """Draw the graph as an ASCII art string."""
517
- from langchain_core.runnables.graph_ascii import draw_ascii
513
+ """Draw the graph as an ASCII art string.
514
+
515
+ Returns:
516
+ The ASCII art string.
517
+ """
518
+ # Import locally to prevent circular import
519
+ from langchain_core.runnables.graph_ascii import draw_ascii # noqa: PLC0415
518
520
 
519
521
  return draw_ascii(
520
522
  {node.id: node.name for node in self.nodes.values()},
@@ -558,7 +560,8 @@ class Graph:
558
560
  Returns:
559
561
  The PNG image as bytes if output_file_path is None, None otherwise.
560
562
  """
561
- from langchain_core.runnables.graph_png import PngDrawer
563
+ # Import locally to prevent circular import
564
+ from langchain_core.runnables.graph_png import PngDrawer # noqa: PLC0415
562
565
 
563
566
  default_node_labels = {node.id: node.name for node in self.nodes.values()}
564
567
 
@@ -613,7 +616,8 @@ class Graph:
613
616
  The Mermaid syntax string.
614
617
 
615
618
  """
616
- from langchain_core.runnables.graph_mermaid import draw_mermaid
619
+ # Import locally to prevent circular import
620
+ from langchain_core.runnables.graph_mermaid import draw_mermaid # noqa: PLC0415
617
621
 
618
622
  graph = self.reid()
619
623
  first_node = graph.first_node()
@@ -684,7 +688,10 @@ class Graph:
684
688
  The PNG image as bytes.
685
689
 
686
690
  """
687
- from langchain_core.runnables.graph_mermaid import draw_mermaid_png
691
+ # Import locally to prevent circular import
692
+ from langchain_core.runnables.graph_mermaid import ( # noqa: PLC0415
693
+ draw_mermaid_png,
694
+ )
688
695
 
689
696
  mermaid_syntax = self.draw_mermaid(
690
697
  curve_style=curve_style,