langchain-core 1.0.0a6__py3-none-any.whl → 1.0.0a8__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.
- langchain_core/_api/__init__.py +3 -3
- langchain_core/_api/beta_decorator.py +6 -6
- langchain_core/_api/deprecation.py +21 -29
- langchain_core/_api/path.py +3 -6
- langchain_core/_import_utils.py +2 -3
- langchain_core/agents.py +10 -11
- langchain_core/caches.py +7 -7
- langchain_core/callbacks/base.py +91 -91
- langchain_core/callbacks/file.py +11 -11
- langchain_core/callbacks/manager.py +86 -89
- langchain_core/callbacks/stdout.py +8 -8
- langchain_core/callbacks/usage.py +4 -4
- langchain_core/chat_history.py +5 -5
- langchain_core/document_loaders/base.py +2 -2
- langchain_core/document_loaders/langsmith.py +15 -15
- langchain_core/documents/base.py +16 -16
- langchain_core/documents/compressor.py +4 -4
- langchain_core/example_selectors/length_based.py +1 -1
- langchain_core/example_selectors/semantic_similarity.py +17 -19
- langchain_core/exceptions.py +3 -3
- langchain_core/globals.py +3 -151
- langchain_core/indexing/api.py +44 -43
- langchain_core/indexing/base.py +30 -30
- langchain_core/indexing/in_memory.py +3 -3
- langchain_core/language_models/_utils.py +5 -7
- langchain_core/language_models/base.py +18 -132
- langchain_core/language_models/chat_models.py +118 -227
- langchain_core/language_models/fake.py +11 -11
- langchain_core/language_models/fake_chat_models.py +35 -29
- langchain_core/language_models/llms.py +91 -201
- langchain_core/load/dump.py +1 -1
- langchain_core/load/load.py +11 -12
- langchain_core/load/mapping.py +2 -4
- langchain_core/load/serializable.py +2 -4
- langchain_core/messages/ai.py +17 -20
- langchain_core/messages/base.py +23 -25
- langchain_core/messages/block_translators/__init__.py +2 -5
- langchain_core/messages/block_translators/anthropic.py +3 -3
- langchain_core/messages/block_translators/bedrock_converse.py +2 -2
- langchain_core/messages/block_translators/langchain_v0.py +2 -2
- langchain_core/messages/block_translators/openai.py +6 -6
- langchain_core/messages/content.py +120 -124
- langchain_core/messages/human.py +7 -7
- langchain_core/messages/system.py +7 -7
- langchain_core/messages/tool.py +24 -24
- langchain_core/messages/utils.py +67 -79
- langchain_core/output_parsers/base.py +12 -14
- langchain_core/output_parsers/json.py +4 -4
- langchain_core/output_parsers/list.py +3 -5
- langchain_core/output_parsers/openai_functions.py +3 -3
- langchain_core/output_parsers/openai_tools.py +3 -3
- langchain_core/output_parsers/pydantic.py +2 -2
- langchain_core/output_parsers/transform.py +13 -15
- langchain_core/output_parsers/xml.py +7 -9
- langchain_core/outputs/chat_generation.py +4 -4
- langchain_core/outputs/chat_result.py +1 -3
- langchain_core/outputs/generation.py +2 -2
- langchain_core/outputs/llm_result.py +5 -5
- langchain_core/prompts/__init__.py +1 -5
- langchain_core/prompts/base.py +10 -15
- langchain_core/prompts/chat.py +31 -82
- langchain_core/prompts/dict.py +2 -2
- langchain_core/prompts/few_shot.py +5 -5
- langchain_core/prompts/few_shot_with_templates.py +4 -4
- langchain_core/prompts/loading.py +3 -5
- langchain_core/prompts/prompt.py +4 -16
- langchain_core/prompts/string.py +2 -1
- langchain_core/prompts/structured.py +16 -23
- langchain_core/rate_limiters.py +3 -4
- langchain_core/retrievers.py +14 -14
- langchain_core/runnables/base.py +928 -1042
- langchain_core/runnables/branch.py +36 -40
- langchain_core/runnables/config.py +27 -35
- langchain_core/runnables/configurable.py +108 -124
- langchain_core/runnables/fallbacks.py +76 -72
- langchain_core/runnables/graph.py +39 -45
- langchain_core/runnables/graph_ascii.py +9 -11
- langchain_core/runnables/graph_mermaid.py +18 -19
- langchain_core/runnables/graph_png.py +8 -9
- langchain_core/runnables/history.py +114 -127
- langchain_core/runnables/passthrough.py +113 -139
- langchain_core/runnables/retry.py +43 -48
- langchain_core/runnables/router.py +23 -28
- langchain_core/runnables/schema.py +42 -44
- langchain_core/runnables/utils.py +28 -31
- langchain_core/stores.py +9 -13
- langchain_core/structured_query.py +8 -8
- langchain_core/tools/base.py +62 -115
- langchain_core/tools/convert.py +31 -35
- langchain_core/tools/render.py +1 -1
- langchain_core/tools/retriever.py +4 -4
- langchain_core/tools/simple.py +13 -17
- langchain_core/tools/structured.py +12 -15
- langchain_core/tracers/base.py +62 -64
- langchain_core/tracers/context.py +17 -35
- langchain_core/tracers/core.py +49 -53
- langchain_core/tracers/evaluation.py +11 -11
- langchain_core/tracers/event_stream.py +58 -60
- langchain_core/tracers/langchain.py +13 -13
- langchain_core/tracers/log_stream.py +22 -24
- langchain_core/tracers/root_listeners.py +14 -14
- langchain_core/tracers/run_collector.py +2 -4
- langchain_core/tracers/schemas.py +8 -8
- langchain_core/tracers/stdout.py +2 -1
- langchain_core/utils/__init__.py +0 -3
- langchain_core/utils/_merge.py +2 -2
- langchain_core/utils/aiter.py +24 -28
- langchain_core/utils/env.py +4 -4
- langchain_core/utils/function_calling.py +31 -41
- langchain_core/utils/html.py +3 -4
- langchain_core/utils/input.py +3 -3
- langchain_core/utils/iter.py +15 -19
- langchain_core/utils/json.py +3 -2
- langchain_core/utils/json_schema.py +6 -6
- langchain_core/utils/mustache.py +3 -5
- langchain_core/utils/pydantic.py +16 -18
- langchain_core/utils/usage.py +1 -1
- langchain_core/utils/utils.py +29 -29
- langchain_core/vectorstores/base.py +18 -21
- langchain_core/vectorstores/in_memory.py +14 -87
- langchain_core/vectorstores/utils.py +2 -2
- langchain_core/version.py +1 -1
- {langchain_core-1.0.0a6.dist-info → langchain_core-1.0.0a8.dist-info}/METADATA +10 -21
- langchain_core-1.0.0a8.dist-info/RECORD +176 -0
- {langchain_core-1.0.0a6.dist-info → langchain_core-1.0.0a8.dist-info}/WHEEL +1 -1
- langchain_core/messages/block_translators/ollama.py +0 -47
- langchain_core/prompts/pipeline.py +0 -138
- langchain_core/tracers/langchain_v1.py +0 -31
- langchain_core/utils/loading.py +0 -35
- langchain_core-1.0.0a6.dist-info/RECORD +0 -181
- langchain_core-1.0.0a6.dist-info/entry_points.txt +0 -4
|
@@ -5,13 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import inspect
|
|
7
7
|
import threading
|
|
8
|
-
from collections.abc import Awaitable
|
|
8
|
+
from collections.abc import Awaitable, Callable
|
|
9
9
|
from typing import (
|
|
10
10
|
TYPE_CHECKING,
|
|
11
11
|
Any,
|
|
12
|
-
Callable,
|
|
13
|
-
Optional,
|
|
14
|
-
Union,
|
|
15
12
|
cast,
|
|
16
13
|
)
|
|
17
14
|
|
|
@@ -86,69 +83,66 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
86
83
|
and experiment with.
|
|
87
84
|
|
|
88
85
|
Examples:
|
|
86
|
+
```python
|
|
87
|
+
from langchain_core.runnables import (
|
|
88
|
+
RunnableLambda,
|
|
89
|
+
RunnableParallel,
|
|
90
|
+
RunnablePassthrough,
|
|
91
|
+
)
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
RunnableLambda,
|
|
94
|
-
RunnableParallel,
|
|
95
|
-
RunnablePassthrough,
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
runnable = RunnableParallel(
|
|
99
|
-
origin=RunnablePassthrough(), modified=lambda x: x + 1
|
|
100
|
-
)
|
|
93
|
+
runnable = RunnableParallel(
|
|
94
|
+
origin=RunnablePassthrough(), modified=lambda x: x + 1
|
|
95
|
+
)
|
|
101
96
|
|
|
102
|
-
|
|
97
|
+
runnable.invoke(1) # {'origin': 1, 'modified': 2}
|
|
103
98
|
|
|
104
99
|
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
def fake_llm(prompt: str) -> str: # Fake LLM for the example
|
|
101
|
+
return "completion"
|
|
107
102
|
|
|
108
103
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
chain = RunnableLambda(fake_llm) | {
|
|
105
|
+
"original": RunnablePassthrough(), # Original LLM output
|
|
106
|
+
"parsed": lambda text: text[::-1], # Parsing logic
|
|
107
|
+
}
|
|
113
108
|
|
|
114
|
-
|
|
109
|
+
chain.invoke("hello") # {'original': 'completion', 'parsed': 'noitelpmoc'}
|
|
110
|
+
```
|
|
115
111
|
|
|
116
112
|
In some cases, it may be useful to pass the input through while adding some
|
|
117
113
|
keys to the output. In this case, you can use the `assign` method:
|
|
118
114
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
from langchain_core.runnables import RunnablePassthrough
|
|
115
|
+
```python
|
|
116
|
+
from langchain_core.runnables import RunnablePassthrough
|
|
122
117
|
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
def fake_llm(prompt: str) -> str: # Fake LLM for the example
|
|
120
|
+
return "completion"
|
|
126
121
|
|
|
127
122
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
runnable.invoke("hello")
|
|
136
|
-
# {'llm1': 'completion', 'llm2': 'completion', 'total_chars': 20}
|
|
123
|
+
runnable = {
|
|
124
|
+
"llm1": fake_llm,
|
|
125
|
+
"llm2": fake_llm,
|
|
126
|
+
} | RunnablePassthrough.assign(
|
|
127
|
+
total_chars=lambda inputs: len(inputs["llm1"] + inputs["llm2"])
|
|
128
|
+
)
|
|
137
129
|
|
|
130
|
+
runnable.invoke("hello")
|
|
131
|
+
# {'llm1': 'completion', 'llm2': 'completion', 'total_chars': 20}
|
|
132
|
+
```
|
|
138
133
|
"""
|
|
139
134
|
|
|
140
|
-
input_type:
|
|
135
|
+
input_type: type[Other] | None = None
|
|
141
136
|
|
|
142
|
-
func:
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
func: Callable[[Other], None] | Callable[[Other, RunnableConfig], None] | None = (
|
|
138
|
+
None
|
|
139
|
+
)
|
|
145
140
|
|
|
146
|
-
afunc:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
] = None
|
|
141
|
+
afunc: (
|
|
142
|
+
Callable[[Other], Awaitable[None]]
|
|
143
|
+
| Callable[[Other, RunnableConfig], Awaitable[None]]
|
|
144
|
+
| None
|
|
145
|
+
) = None
|
|
152
146
|
|
|
153
147
|
@override
|
|
154
148
|
def __repr_args__(self) -> Any:
|
|
@@ -158,23 +152,16 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
158
152
|
|
|
159
153
|
def __init__(
|
|
160
154
|
self,
|
|
161
|
-
func:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
] = None,
|
|
170
|
-
afunc: Optional[
|
|
171
|
-
Union[
|
|
172
|
-
Callable[[Other], Awaitable[None]],
|
|
173
|
-
Callable[[Other, RunnableConfig], Awaitable[None]],
|
|
174
|
-
]
|
|
175
|
-
] = None,
|
|
155
|
+
func: Callable[[Other], None]
|
|
156
|
+
| Callable[[Other, RunnableConfig], None]
|
|
157
|
+
| Callable[[Other], Awaitable[None]]
|
|
158
|
+
| Callable[[Other, RunnableConfig], Awaitable[None]]
|
|
159
|
+
| None = None,
|
|
160
|
+
afunc: Callable[[Other], Awaitable[None]]
|
|
161
|
+
| Callable[[Other, RunnableConfig], Awaitable[None]]
|
|
162
|
+
| None = None,
|
|
176
163
|
*,
|
|
177
|
-
input_type:
|
|
164
|
+
input_type: type[Other] | None = None,
|
|
178
165
|
**kwargs: Any,
|
|
179
166
|
) -> None:
|
|
180
167
|
"""Create e RunnablePassthrough.
|
|
@@ -219,14 +206,9 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
219
206
|
@override
|
|
220
207
|
def assign(
|
|
221
208
|
cls,
|
|
222
|
-
**kwargs:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
Mapping[
|
|
226
|
-
str,
|
|
227
|
-
Union[Runnable[dict[str, Any], Any], Callable[[dict[str, Any]], Any]],
|
|
228
|
-
],
|
|
229
|
-
],
|
|
209
|
+
**kwargs: Runnable[dict[str, Any], Any]
|
|
210
|
+
| Callable[[dict[str, Any]], Any]
|
|
211
|
+
| Mapping[str, Runnable[dict[str, Any], Any] | Callable[[dict[str, Any]], Any]],
|
|
230
212
|
) -> RunnableAssign:
|
|
231
213
|
"""Merge the Dict input with the output produced by the mapping argument.
|
|
232
214
|
|
|
@@ -242,7 +224,7 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
242
224
|
|
|
243
225
|
@override
|
|
244
226
|
def invoke(
|
|
245
|
-
self, input: Other, config:
|
|
227
|
+
self, input: Other, config: RunnableConfig | None = None, **kwargs: Any
|
|
246
228
|
) -> Other:
|
|
247
229
|
if self.func is not None:
|
|
248
230
|
call_func_with_variable_args(
|
|
@@ -254,8 +236,8 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
254
236
|
async def ainvoke(
|
|
255
237
|
self,
|
|
256
238
|
input: Other,
|
|
257
|
-
config:
|
|
258
|
-
**kwargs:
|
|
239
|
+
config: RunnableConfig | None = None,
|
|
240
|
+
**kwargs: Any | None,
|
|
259
241
|
) -> Other:
|
|
260
242
|
if self.afunc is not None:
|
|
261
243
|
await acall_func_with_variable_args(
|
|
@@ -271,7 +253,7 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
271
253
|
def transform(
|
|
272
254
|
self,
|
|
273
255
|
input: Iterator[Other],
|
|
274
|
-
config:
|
|
256
|
+
config: RunnableConfig | None = None,
|
|
275
257
|
**kwargs: Any,
|
|
276
258
|
) -> Iterator[Other]:
|
|
277
259
|
if self.func is None:
|
|
@@ -302,7 +284,7 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
302
284
|
async def atransform(
|
|
303
285
|
self,
|
|
304
286
|
input: AsyncIterator[Other],
|
|
305
|
-
config:
|
|
287
|
+
config: RunnableConfig | None = None,
|
|
306
288
|
**kwargs: Any,
|
|
307
289
|
) -> AsyncIterator[Other]:
|
|
308
290
|
if self.afunc is None and self.func is None:
|
|
@@ -345,7 +327,7 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
345
327
|
def stream(
|
|
346
328
|
self,
|
|
347
329
|
input: Other,
|
|
348
|
-
config:
|
|
330
|
+
config: RunnableConfig | None = None,
|
|
349
331
|
**kwargs: Any,
|
|
350
332
|
) -> Iterator[Other]:
|
|
351
333
|
return self.transform(iter([input]), config, **kwargs)
|
|
@@ -354,7 +336,7 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]):
|
|
|
354
336
|
async def astream(
|
|
355
337
|
self,
|
|
356
338
|
input: Other,
|
|
357
|
-
config:
|
|
339
|
+
config: RunnableConfig | None = None,
|
|
358
340
|
**kwargs: Any,
|
|
359
341
|
) -> AsyncIterator[Other]:
|
|
360
342
|
async def input_aiter() -> AsyncIterator[Other]:
|
|
@@ -376,36 +358,35 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
376
358
|
on the mapper's logic.
|
|
377
359
|
|
|
378
360
|
Examples:
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
from langchain_core.runnables.base import RunnableLambda
|
|
361
|
+
```python
|
|
362
|
+
# This is a RunnableAssign
|
|
363
|
+
from langchain_core.runnables.passthrough import (
|
|
364
|
+
RunnableAssign,
|
|
365
|
+
RunnableParallel,
|
|
366
|
+
)
|
|
367
|
+
from langchain_core.runnables.base import RunnableLambda
|
|
387
368
|
|
|
388
369
|
|
|
389
|
-
|
|
390
|
-
|
|
370
|
+
def add_ten(x: dict[str, int]) -> dict[str, int]:
|
|
371
|
+
return {"added": x["input"] + 10}
|
|
391
372
|
|
|
392
373
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
runnable_assign = RunnableAssign(mapper)
|
|
374
|
+
mapper = RunnableParallel(
|
|
375
|
+
{
|
|
376
|
+
"add_step": RunnableLambda(add_ten),
|
|
377
|
+
}
|
|
378
|
+
)
|
|
400
379
|
|
|
401
|
-
|
|
402
|
-
runnable_assign.invoke({"input": 5})
|
|
403
|
-
# returns {'input': 5, 'add_step': {'added': 15}}
|
|
380
|
+
runnable_assign = RunnableAssign(mapper)
|
|
404
381
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
382
|
+
# Synchronous example
|
|
383
|
+
runnable_assign.invoke({"input": 5})
|
|
384
|
+
# returns {'input': 5, 'add_step': {'added': 15}}
|
|
408
385
|
|
|
386
|
+
# Asynchronous example
|
|
387
|
+
await runnable_assign.ainvoke({"input": 5})
|
|
388
|
+
# returns {'input': 5, 'add_step': {'added': 15}}
|
|
389
|
+
```
|
|
409
390
|
"""
|
|
410
391
|
|
|
411
392
|
mapper: RunnableParallel
|
|
@@ -436,9 +417,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
436
417
|
return ["langchain", "schema", "runnable"]
|
|
437
418
|
|
|
438
419
|
@override
|
|
439
|
-
def get_name(
|
|
440
|
-
self, suffix: Optional[str] = None, *, name: Optional[str] = None
|
|
441
|
-
) -> str:
|
|
420
|
+
def get_name(self, suffix: str | None = None, *, name: str | None = None) -> str:
|
|
442
421
|
name = (
|
|
443
422
|
name
|
|
444
423
|
or self.name
|
|
@@ -447,9 +426,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
447
426
|
return super().get_name(suffix, name=name)
|
|
448
427
|
|
|
449
428
|
@override
|
|
450
|
-
def get_input_schema(
|
|
451
|
-
self, config: Optional[RunnableConfig] = None
|
|
452
|
-
) -> type[BaseModel]:
|
|
429
|
+
def get_input_schema(self, config: RunnableConfig | None = None) -> type[BaseModel]:
|
|
453
430
|
map_input_schema = self.mapper.get_input_schema(config)
|
|
454
431
|
if not issubclass(map_input_schema, RootModel):
|
|
455
432
|
# ie. it's a dict
|
|
@@ -459,7 +436,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
459
436
|
|
|
460
437
|
@override
|
|
461
438
|
def get_output_schema(
|
|
462
|
-
self, config:
|
|
439
|
+
self, config: RunnableConfig | None = None
|
|
463
440
|
) -> type[BaseModel]:
|
|
464
441
|
map_input_schema = self.mapper.get_input_schema(config)
|
|
465
442
|
map_output_schema = self.mapper.get_output_schema(config)
|
|
@@ -524,7 +501,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
524
501
|
def invoke(
|
|
525
502
|
self,
|
|
526
503
|
input: dict[str, Any],
|
|
527
|
-
config:
|
|
504
|
+
config: RunnableConfig | None = None,
|
|
528
505
|
**kwargs: Any,
|
|
529
506
|
) -> dict[str, Any]:
|
|
530
507
|
return self._call_with_config(self._invoke, input, config, **kwargs)
|
|
@@ -553,7 +530,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
553
530
|
async def ainvoke(
|
|
554
531
|
self,
|
|
555
532
|
input: dict[str, Any],
|
|
556
|
-
config:
|
|
533
|
+
config: RunnableConfig | None = None,
|
|
557
534
|
**kwargs: Any,
|
|
558
535
|
) -> dict[str, Any]:
|
|
559
536
|
return await self._acall_with_config(self._ainvoke, input, config, **kwargs)
|
|
@@ -608,7 +585,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
608
585
|
def transform(
|
|
609
586
|
self,
|
|
610
587
|
input: Iterator[dict[str, Any]],
|
|
611
|
-
config:
|
|
588
|
+
config: RunnableConfig | None = None,
|
|
612
589
|
**kwargs: Any | None,
|
|
613
590
|
) -> Iterator[dict[str, Any]]:
|
|
614
591
|
yield from self._transform_stream_with_config(
|
|
@@ -660,7 +637,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
660
637
|
async def atransform(
|
|
661
638
|
self,
|
|
662
639
|
input: AsyncIterator[dict[str, Any]],
|
|
663
|
-
config:
|
|
640
|
+
config: RunnableConfig | None = None,
|
|
664
641
|
**kwargs: Any,
|
|
665
642
|
) -> AsyncIterator[dict[str, Any]]:
|
|
666
643
|
async for chunk in self._atransform_stream_with_config(
|
|
@@ -672,7 +649,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
672
649
|
def stream(
|
|
673
650
|
self,
|
|
674
651
|
input: dict[str, Any],
|
|
675
|
-
config:
|
|
652
|
+
config: RunnableConfig | None = None,
|
|
676
653
|
**kwargs: Any,
|
|
677
654
|
) -> Iterator[dict[str, Any]]:
|
|
678
655
|
return self.transform(iter([input]), config, **kwargs)
|
|
@@ -681,7 +658,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
681
658
|
async def astream(
|
|
682
659
|
self,
|
|
683
660
|
input: dict[str, Any],
|
|
684
|
-
config:
|
|
661
|
+
config: RunnableConfig | None = None,
|
|
685
662
|
**kwargs: Any,
|
|
686
663
|
) -> AsyncIterator[dict[str, Any]]:
|
|
687
664
|
async def input_aiter() -> AsyncIterator[dict[str, Any]]:
|
|
@@ -700,28 +677,27 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
700
677
|
the selected keys.
|
|
701
678
|
|
|
702
679
|
Example:
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
runnable = RunnablePick(keys=["name", "age"])
|
|
680
|
+
```python
|
|
681
|
+
from langchain_core.runnables.passthrough import RunnablePick
|
|
682
|
+
|
|
683
|
+
input_data = {
|
|
684
|
+
"name": "John",
|
|
685
|
+
"age": 30,
|
|
686
|
+
"city": "New York",
|
|
687
|
+
"country": "USA",
|
|
688
|
+
}
|
|
715
689
|
|
|
716
|
-
|
|
690
|
+
runnable = RunnablePick(keys=["name", "age"])
|
|
717
691
|
|
|
718
|
-
|
|
692
|
+
output_data = runnable.invoke(input_data)
|
|
719
693
|
|
|
694
|
+
print(output_data) # Output: {'name': 'John', 'age': 30}
|
|
695
|
+
```
|
|
720
696
|
"""
|
|
721
697
|
|
|
722
|
-
keys:
|
|
698
|
+
keys: str | list[str]
|
|
723
699
|
|
|
724
|
-
def __init__(self, keys:
|
|
700
|
+
def __init__(self, keys: str | list[str], **kwargs: Any) -> None:
|
|
725
701
|
"""Create a RunnablePick.
|
|
726
702
|
|
|
727
703
|
Args:
|
|
@@ -746,9 +722,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
746
722
|
return ["langchain", "schema", "runnable"]
|
|
747
723
|
|
|
748
724
|
@override
|
|
749
|
-
def get_name(
|
|
750
|
-
self, suffix: Optional[str] = None, *, name: Optional[str] = None
|
|
751
|
-
) -> str:
|
|
725
|
+
def get_name(self, suffix: str | None = None, *, name: str | None = None) -> str:
|
|
752
726
|
name = (
|
|
753
727
|
name
|
|
754
728
|
or self.name
|
|
@@ -779,7 +753,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
779
753
|
def invoke(
|
|
780
754
|
self,
|
|
781
755
|
input: dict[str, Any],
|
|
782
|
-
config:
|
|
756
|
+
config: RunnableConfig | None = None,
|
|
783
757
|
**kwargs: Any,
|
|
784
758
|
) -> dict[str, Any]:
|
|
785
759
|
return self._call_with_config(self._invoke, input, config, **kwargs)
|
|
@@ -794,7 +768,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
794
768
|
async def ainvoke(
|
|
795
769
|
self,
|
|
796
770
|
input: dict[str, Any],
|
|
797
|
-
config:
|
|
771
|
+
config: RunnableConfig | None = None,
|
|
798
772
|
**kwargs: Any,
|
|
799
773
|
) -> dict[str, Any]:
|
|
800
774
|
return await self._acall_with_config(self._ainvoke, input, config, **kwargs)
|
|
@@ -812,7 +786,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
812
786
|
def transform(
|
|
813
787
|
self,
|
|
814
788
|
input: Iterator[dict[str, Any]],
|
|
815
|
-
config:
|
|
789
|
+
config: RunnableConfig | None = None,
|
|
816
790
|
**kwargs: Any,
|
|
817
791
|
) -> Iterator[dict[str, Any]]:
|
|
818
792
|
yield from self._transform_stream_with_config(
|
|
@@ -832,7 +806,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
832
806
|
async def atransform(
|
|
833
807
|
self,
|
|
834
808
|
input: AsyncIterator[dict[str, Any]],
|
|
835
|
-
config:
|
|
809
|
+
config: RunnableConfig | None = None,
|
|
836
810
|
**kwargs: Any,
|
|
837
811
|
) -> AsyncIterator[dict[str, Any]]:
|
|
838
812
|
async for chunk in self._atransform_stream_with_config(
|
|
@@ -844,7 +818,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
844
818
|
def stream(
|
|
845
819
|
self,
|
|
846
820
|
input: dict[str, Any],
|
|
847
|
-
config:
|
|
821
|
+
config: RunnableConfig | None = None,
|
|
848
822
|
**kwargs: Any,
|
|
849
823
|
) -> Iterator[dict[str, Any]]:
|
|
850
824
|
return self.transform(iter([input]), config, **kwargs)
|
|
@@ -853,7 +827,7 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]):
|
|
|
853
827
|
async def astream(
|
|
854
828
|
self,
|
|
855
829
|
input: dict[str, Any],
|
|
856
|
-
config:
|
|
830
|
+
config: RunnableConfig | None = None,
|
|
857
831
|
**kwargs: Any,
|
|
858
832
|
) -> AsyncIterator[dict[str, Any]]:
|
|
859
833
|
async def input_aiter() -> AsyncIterator[dict[str, Any]]:
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
from typing import (
|
|
4
4
|
TYPE_CHECKING,
|
|
5
5
|
Any,
|
|
6
|
-
Optional,
|
|
7
6
|
TypeVar,
|
|
8
|
-
Union,
|
|
9
7
|
cast,
|
|
10
8
|
)
|
|
11
9
|
|
|
@@ -62,36 +60,34 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
62
60
|
Example:
|
|
63
61
|
Here's an example that uses a RunnableLambda to raise an exception
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
```python
|
|
64
|
+
import time
|
|
66
65
|
|
|
67
|
-
import time
|
|
68
66
|
|
|
67
|
+
def foo(input) -> None:
|
|
68
|
+
'''Fake function that raises an exception.'''
|
|
69
|
+
raise ValueError(f"Invoking foo failed. At time {time.time()}")
|
|
69
70
|
|
|
70
|
-
def foo(input) -> None:
|
|
71
|
-
'''Fake function that raises an exception.'''
|
|
72
|
-
raise ValueError(f"Invoking foo failed. At time {time.time()}")
|
|
73
71
|
|
|
72
|
+
runnable = RunnableLambda(foo)
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
exponential_jitter_params={
|
|
82
|
-
"initial": 2
|
|
83
|
-
}, # if desired, customize backoff
|
|
84
|
-
)
|
|
74
|
+
runnable_with_retries = runnable.with_retry(
|
|
75
|
+
retry_if_exception_type=(ValueError,), # Retry only on ValueError
|
|
76
|
+
wait_exponential_jitter=True, # Add jitter to the exponential backoff
|
|
77
|
+
stop_after_attempt=2, # Try twice
|
|
78
|
+
exponential_jitter_params={"initial": 2}, # if desired, customize backoff
|
|
79
|
+
)
|
|
85
80
|
|
|
86
|
-
|
|
81
|
+
# The method invocation above is equivalent to the longer form below:
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
runnable_with_retries = RunnableRetry(
|
|
84
|
+
bound=runnable,
|
|
85
|
+
retry_exception_types=(ValueError,),
|
|
86
|
+
max_attempt_number=2,
|
|
87
|
+
wait_exponential_jitter=True,
|
|
88
|
+
exponential_jitter_params={"initial": 2},
|
|
89
|
+
)
|
|
90
|
+
```
|
|
95
91
|
|
|
96
92
|
This logic can be used to retry any Runnable, including a chain of Runnables,
|
|
97
93
|
but in general it's best practice to keep the scope of the retry as small as
|
|
@@ -99,22 +95,20 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
99
95
|
the Runnable that is likely to fail, not the entire chain.
|
|
100
96
|
|
|
101
97
|
Example:
|
|
98
|
+
```python
|
|
99
|
+
from langchain_core.chat_models import ChatOpenAI
|
|
100
|
+
from langchain_core.prompts import PromptTemplate
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
from langchain_core.chat_models import ChatOpenAI
|
|
106
|
-
from langchain_core.prompts import PromptTemplate
|
|
107
|
-
|
|
108
|
-
template = PromptTemplate.from_template("tell me a joke about {topic}.")
|
|
109
|
-
model = ChatOpenAI(temperature=0.5)
|
|
110
|
-
|
|
111
|
-
# Good
|
|
112
|
-
chain = template | model.with_retry()
|
|
102
|
+
template = PromptTemplate.from_template("tell me a joke about {topic}.")
|
|
103
|
+
model = ChatOpenAI(temperature=0.5)
|
|
113
104
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
retryable_chain = chain.with_retry()
|
|
105
|
+
# Good
|
|
106
|
+
chain = template | model.with_retry()
|
|
117
107
|
|
|
108
|
+
# Bad
|
|
109
|
+
chain = template | model
|
|
110
|
+
retryable_chain = chain.with_retry()
|
|
111
|
+
```
|
|
118
112
|
"""
|
|
119
113
|
|
|
120
114
|
retry_exception_types: tuple[type[BaseException], ...] = (Exception,)
|
|
@@ -130,7 +124,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
130
124
|
wait_exponential_jitter: bool = True
|
|
131
125
|
"""Whether to add jitter to the exponential backoff."""
|
|
132
126
|
|
|
133
|
-
exponential_jitter_params:
|
|
127
|
+
exponential_jitter_params: ExponentialJitterParams | None = None
|
|
134
128
|
"""Parameters for ``tenacity.wait_exponential_jitter``. Namely: ``initial``,
|
|
135
129
|
``max``, ``exp_base``, and ``jitter`` (all float values).
|
|
136
130
|
"""
|
|
@@ -178,7 +172,8 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
178
172
|
retry_state: RetryCallState,
|
|
179
173
|
) -> list[RunnableConfig]:
|
|
180
174
|
return [
|
|
181
|
-
self._patch_config(c, rm, retry_state)
|
|
175
|
+
self._patch_config(c, rm, retry_state)
|
|
176
|
+
for c, rm in zip(config, run_manager, strict=False)
|
|
182
177
|
]
|
|
183
178
|
|
|
184
179
|
def _invoke(
|
|
@@ -201,7 +196,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
201
196
|
|
|
202
197
|
@override
|
|
203
198
|
def invoke(
|
|
204
|
-
self, input: Input, config:
|
|
199
|
+
self, input: Input, config: RunnableConfig | None = None, **kwargs: Any
|
|
205
200
|
) -> Output:
|
|
206
201
|
return self._call_with_config(self._invoke, input, config, **kwargs)
|
|
207
202
|
|
|
@@ -225,7 +220,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
225
220
|
|
|
226
221
|
@override
|
|
227
222
|
async def ainvoke(
|
|
228
|
-
self, input: Input, config:
|
|
223
|
+
self, input: Input, config: RunnableConfig | None = None, **kwargs: Any
|
|
229
224
|
) -> Output:
|
|
230
225
|
return await self._acall_with_config(self._ainvoke, input, config, **kwargs)
|
|
231
226
|
|
|
@@ -235,7 +230,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
235
230
|
run_manager: list["CallbackManagerForChainRun"],
|
|
236
231
|
config: list[RunnableConfig],
|
|
237
232
|
**kwargs: Any,
|
|
238
|
-
) -> list[
|
|
233
|
+
) -> list[Output | Exception]:
|
|
239
234
|
results_map: dict[int, Output] = {}
|
|
240
235
|
|
|
241
236
|
not_set: list[Output] = []
|
|
@@ -284,7 +279,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
284
279
|
if result is not_set:
|
|
285
280
|
result = cast("list[Output]", [e] * len(inputs))
|
|
286
281
|
|
|
287
|
-
outputs: list[
|
|
282
|
+
outputs: list[Output | Exception] = []
|
|
288
283
|
for idx in range(len(inputs)):
|
|
289
284
|
if idx in results_map:
|
|
290
285
|
outputs.append(results_map[idx])
|
|
@@ -296,7 +291,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
296
291
|
def batch(
|
|
297
292
|
self,
|
|
298
293
|
inputs: list[Input],
|
|
299
|
-
config:
|
|
294
|
+
config: RunnableConfig | list[RunnableConfig] | None = None,
|
|
300
295
|
*,
|
|
301
296
|
return_exceptions: bool = False,
|
|
302
297
|
**kwargs: Any,
|
|
@@ -311,7 +306,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
311
306
|
run_manager: list["AsyncCallbackManagerForChainRun"],
|
|
312
307
|
config: list[RunnableConfig],
|
|
313
308
|
**kwargs: Any,
|
|
314
|
-
) -> list[
|
|
309
|
+
) -> list[Output | Exception]:
|
|
315
310
|
results_map: dict[int, Output] = {}
|
|
316
311
|
|
|
317
312
|
not_set: list[Output] = []
|
|
@@ -359,7 +354,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
359
354
|
if result is not_set:
|
|
360
355
|
result = cast("list[Output]", [e] * len(inputs))
|
|
361
356
|
|
|
362
|
-
outputs: list[
|
|
357
|
+
outputs: list[Output | Exception] = []
|
|
363
358
|
for idx in range(len(inputs)):
|
|
364
359
|
if idx in results_map:
|
|
365
360
|
outputs.append(results_map[idx])
|
|
@@ -371,7 +366,7 @@ class RunnableRetry(RunnableBindingBase[Input, Output]): # type: ignore[no-rede
|
|
|
371
366
|
async def abatch(
|
|
372
367
|
self,
|
|
373
368
|
inputs: list[Input],
|
|
374
|
-
config:
|
|
369
|
+
config: RunnableConfig | list[RunnableConfig] | None = None,
|
|
375
370
|
*,
|
|
376
371
|
return_exceptions: bool = False,
|
|
377
372
|
**kwargs: Any,
|