core: fix attributeerror in runnablelambda.deps (#20569)

- would happen when user's code tries to access attritbute that doesnt
exist, we prefer to let this crash in the user's code, rather than here
- also catch more cases where a runnable is invoked/streamed inside a
lambda. before we weren't seeing these as deps
pull/20374/head^2
Nuno Campos 3 months ago committed by GitHub
parent 8b09e81496
commit 719da8746e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3752,7 +3752,13 @@ class RunnableLambda(Runnable[Input, Output]):
else:
objects = []
return [obj for obj in objects if isinstance(obj, Runnable)]
deps: List[Runnable] = []
for obj in objects:
if isinstance(obj, Runnable):
deps.append(obj)
elif isinstance(getattr(obj, "__self__", None), Runnable):
deps.append(obj.__self__)
return deps
@property
def config_specs(self) -> List[ConfigurableFieldSpec]:

@ -263,7 +263,10 @@ def get_function_nonlocals(func: Callable) -> List[Any]:
if vv is None:
break
else:
vv = getattr(vv, part)
try:
vv = getattr(vv, part)
except AttributeError:
break
else:
values.append(vv)
return values

@ -1,9 +1,11 @@
import sys
from typing import Callable
from typing import Callable, Dict
import pytest
from langchain_core.runnables.base import RunnableLambda
from langchain_core.runnables.utils import (
get_function_nonlocals,
get_lambda_source,
indent_lines_after_first,
)
@ -37,3 +39,21 @@ def test_indent_lines_after_first(text: str, prefix: str, expected_output: str)
"""Test indent_lines_after_first function"""
indented_text = indent_lines_after_first(text, prefix)
assert indented_text == expected_output
def test_nonlocals() -> None:
agent = RunnableLambda(lambda x: x * 2) # noqa: F841
def my_func(input: str, agent: Dict[str, str]) -> str:
return agent.get("agent_name", input)
def my_func2(input: str) -> str:
return agent.get("agent_name", input) # type: ignore[attr-defined]
def my_func3(input: str) -> str:
return agent.invoke(input)
assert get_function_nonlocals(my_func) == []
assert get_function_nonlocals(my_func2) == []
assert get_function_nonlocals(my_func3) == [agent.invoke]
assert RunnableLambda(my_func3).deps == [agent]

Loading…
Cancel
Save