From ded2a1fb3c06a9562d9079e42099020ecaca4060 Mon Sep 17 00:00:00 2001 From: gaoanze888 Date: Wed, 19 Aug 2026 22:45:58 +0800 Subject: [PATCH] fix(core): allow deserializing `RunnablePick` (#39753) --- libs/core/langchain_core/load/mapping.py | 12 +++++++++ .../unit_tests/load/test_serializable.py | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/libs/core/langchain_core/load/mapping.py b/libs/core/langchain_core/load/mapping.py index 53a9282485..7ae3e6220b 100644 --- a/libs/core/langchain_core/load/mapping.py +++ b/libs/core/langchain_core/load/mapping.py @@ -548,6 +548,12 @@ SERIALIZABLE_MAPPING: dict[tuple[str, ...], tuple[str, ...]] = { "passthrough", "RunnableAssign", ), + ("langchain", "schema", "runnable", "RunnablePick"): ( + "langchain_core", + "runnables", + "passthrough", + "RunnablePick", + ), ("langchain", "schema", "runnable", "RunnableRetry"): ( "langchain_core", "runnables", @@ -963,6 +969,12 @@ OLD_CORE_NAMESPACES_MAPPING: dict[tuple[str, ...], tuple[str, ...]] = { "passthrough", "RunnableAssign", ), + ("langchain_core", "runnables", "passthrough", "RunnablePick"): ( + "langchain_core", + "runnables", + "passthrough", + "RunnablePick", + ), ("langchain_core", "runnables", "retry", "RunnableRetry"): ( "langchain_core", "runnables", diff --git a/libs/core/tests/unit_tests/load/test_serializable.py b/libs/core/tests/unit_tests/load/test_serializable.py index 00cb1c3454..aa53863176 100644 --- a/libs/core/tests/unit_tests/load/test_serializable.py +++ b/libs/core/tests/unit_tests/load/test_serializable.py @@ -23,6 +23,7 @@ from langchain_core.prompts import ( HumanMessagePromptTemplate, PromptTemplate, ) +from langchain_core.runnables import RunnablePassthrough, RunnablePick from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.tracers import log_stream from langchain_core.utils import from_env @@ -1233,3 +1234,27 @@ class TestInternalCallSitesUseMessages: 'allowed_objects="messages"' in source or "allowed_objects='messages'" in source ) + + +def test_runnable_pick_roundtrips() -> None: + """Test `RunnablePick` can be loaded back after being dumped. + + Regression test: `RunnablePick` reports `is_lc_serializable()` and dumps fine, + but was missing from the deserialization mapping, so `load` rejected it while + its siblings in the same module round-tripped. + """ + original = RunnablePick(keys=["a"]) + + revived = load(dumpd(original)) + + assert isinstance(revived, RunnablePick) + assert revived.keys == ["a"] + + +def test_chain_using_pick_roundtrips() -> None: + """Test a chain built with the public `.pick()` helper survives a round trip.""" + chain = RunnablePassthrough().pick(["a"]) + + revived = load(dumpd(chain)) + + assert revived.invoke({"a": 1, "b": 2}) == {"a": 1}