diff --git a/libs/core/langchain_core/utils/function_calling.py b/libs/core/langchain_core/utils/function_calling.py index 860259a93e3..b2b380e2016 100644 --- a/libs/core/langchain_core/utils/function_calling.py +++ b/libs/core/langchain_core/utils/function_calling.py @@ -4,6 +4,7 @@ from __future__ import annotations import inspect import uuid +from types import FunctionType, MethodType from typing import ( TYPE_CHECKING, Any, @@ -200,8 +201,11 @@ def _get_python_function_required_args(function: Callable) -> List[str]: required = spec.args[: -len(spec.defaults)] if spec.defaults else spec.args required += [k for k in spec.kwonlyargs if k not in (spec.kwonlydefaults or {})] - is_class = type(function) is type - if is_class and required[0] == "self": + is_function_type = isinstance(function, FunctionType) + is_method_type = isinstance(function, MethodType) + if is_function_type and required[0] == "self": + required = required[1:] + elif is_method_type and required[0] == "cls": required = required[1:] return required diff --git a/libs/core/tests/unit_tests/utils/test_function_calling.py b/libs/core/tests/unit_tests/utils/test_function_calling.py index 00328bcf29b..1f818fe6bae 100644 --- a/libs/core/tests/unit_tests/utils/test_function_calling.py +++ b/libs/core/tests/unit_tests/utils/test_function_calling.py @@ -71,6 +71,29 @@ def json_schema() -> Dict: } +class Dummy: + def dummy_function(self, arg1: int, arg2: Literal["bar", "baz"]) -> None: + """dummy function + + Args: + arg1: foo + arg2: one of 'bar', 'baz' + """ + pass + + +class DummyWithClassMethod: + @classmethod + def dummy_function(cls, arg1: int, arg2: Literal["bar", "baz"]) -> None: + """dummy function + + Args: + arg1: foo + arg2: one of 'bar', 'baz' + """ + pass + + def test_convert_to_openai_function( pydantic: Type[BaseModel], function: Callable, @@ -94,7 +117,15 @@ def test_convert_to_openai_function( }, } - for fn in (pydantic, function, dummy_tool, json_schema, expected): + for fn in ( + pydantic, + function, + dummy_tool, + json_schema, + expected, + Dummy.dummy_function, + DummyWithClassMethod.dummy_function, + ): actual = convert_to_openai_function(fn) # type: ignore assert actual == expected