-
Notifications
You must be signed in to change notification settings - Fork 3k
Store reference to original function when creating FunctionTool
#2146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
seratch
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for sending this pull request. Ideally, enabling my_func('hello ', 'world!') is the best. I will also explore solutions for it. As for your changes, make lint seems to be failing. Can you resolve it?
|
@seratch Thanks for the quick response. To achieve the functionality you are describing we could adopt the following approach: import inspect
from dataclasses import dataclass
import functools
@dataclass
class FunctionTool:
....
func: ToolFunction[...] | None = None
def __post_init__(self):
if self.func:
functools.update_wrapper(self, self.func)
def __call__(self, *args, **kwargs):
if not self.func:
raise FunctionNotSetError()
return self.func(*args, **kwargs)
def func(x: str) -> str:
"""this is a test"""
return x
func = FunctionTool(...,func=func)
sig = inspect.signature(func)
sig_func = inspect.signature(func.func)
assert sig == sig_func
assert func.__doc__ == func.func.__doc__This will ensure that signatures and docs of the original function are retained. What do you think? |
|
Yeah you're right. I actually did the same for Slack's official SDKs before joining OpenAI :) If you could apply the approach rather than holding func object in FunctionTool instance, it should be better for dev experience. I don't think this approach could cause any side effects but we can verify if nothing is broken due to that. |
|
@seratch I implemented the solution I proposed. A few notes:
|
|
Seems like this test is unrelated but was still failing? Can you see any reason why my changes would cause this test to error? For some reason pytest interpreted |
This looks like an issue with the combination of the changes here and pytest.fixture mechanism. While the failure affects only tests so far, I'd like to avoid ignoring the error because similar issues could arise with some other libraries. |
|
Yeah it seems like it's an issue with |
|
This PR is stale because it has been open for 10 days with no activity. |
|
@varunursekar If you're still interested in working on this, we're happy to have your enhancement here! |
|
@seratch It seems like |
|
This PR is stale because it has been open for 10 days with no activity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caa28733af
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| on_invoke_tool=_on_invoke_tool, | ||
| strict_json_schema=strict_mode, | ||
| is_enabled=is_enabled, | ||
| _func=func, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Store wrapped function when decorator is parameterized
When @function_tool(...) is used with parentheses, the outer func is None, but _create_function_tool stores _func=func. That leaves _func unset for the common decorator-with-args path, so FunctionTool.__post_init__ won’t copy __name__/__doc__, and the new __call__ will raise AttributeError even though the tool was created from a real function. This breaks the stated goal for users who pass any decorator options (e.g. @function_tool(name_override=...)). The wrapped function should be stored from the inner the_func/real_func instead.
Useful? React with 👍 / 👎.
When
@function_toolis used, no reference to the original function is retained, which makes testing the function directly cumbersome. The original function is now just stored as an attribute ofFunctionTool:The alternative is to require users to define helper functions duplicating signatures and doc strings: