Ignore self/cls from required args of class functions in convert_to_openai_tool (#20691)

Removed redundant self/cls from required args of class functions in
_get_python_function_required_args:

```python
class MemberTool:
    def search_member(
            self,
            keyword: str,
            *args,
            **kwargs,
    ):
        """Search on members with any keyword like first_name, last_name, email

        Args:
            keyword: Any keyword of member
        """

        headers = dict(authorization=kwargs['token'])
        members = []
        try:
            members = request_(
                method='SEARCH',
                url=f'{service_url}/apiv1/members',
                headers=headers,
                json=dict(query=keyword),
            )

        except Exception as e:
            logger.info(e.__doc__)

        return members

convert_to_openai_tool(MemberTool.search_member)
```
expected result:
```
{'type': 'function', 'function': {'name': 'search_member', 'description': 'Search on members with any keyword like first_name, last_name, username, email', 'parameters': {'type': 'object', 'properties': {'keyword': {'type': 'string', 'description': 'Any keyword of member'}}, 'required': ['keyword']}}}
```

#20685

---------

Co-authored-by: Bagatur <22008038+baskaryan@users.noreply.github.com>
Co-authored-by: Bagatur <baskaryan@gmail.com>
This commit is contained in:
hmn falahi 2024-04-29 19:16:26 +03:30 committed by GitHub
parent a64a1943fd
commit 4822beb298
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 3 deletions

View File

@ -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

View File

@ -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