[fix] Preserve function metadata in Toolkit bound methods via functools.wraps#7570
[fix] Preserve function metadata in Toolkit bound methods via functools.wraps#7570nklowns wants to merge 1 commit intoagno-agi:mainfrom
Conversation
…s.wraps Replaces manual __name__/__doc__ assignment with functools.wraps so that bound methods created for @tool-decorated Toolkit methods correctly preserve __qualname__, __annotations__, and __wrapped__. Fixes agno-agi#7569 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5c564e9 to
f623668
Compare
VANDRANKI
left a comment
There was a problem hiding this comment.
The diagnosis and fix are correct. functools.wraps is exactly the right tool here - it copies __module__, __name__, __qualname__, __annotations__, __doc__, __dict__ and sets __wrapped__ in one call, which is precisely what the manual assignment approach was missing.
One subtlety worth noting
After @functools.wraps(func), inspect.signature(bound) will reflect the original function signature - including self as the first parameter - rather than the bound callable's actual signature (which drops self). Python's descriptor protocol drops self when accessing a method through an instance, but functools.wraps does not replicate that. If any downstream code calls inspect.signature() on the entrypoint to build tool parameter schemas, it will see self in the signature. Worth checking whether Function schema extraction introspects the entrypoint directly.
Tests
The test structure is clean - one assertion per test function makes failures easy to pinpoint. One small gap: the async branch has no test_async_bound_method_preserves_doc counterpart to the sync test_sync_bound_method_preserves_doc. Not a blocker, but easy to add for completeness.
Both branches (sync and async) are fixed consistently, __wrapped__ is set (so inspect.unwrap() works), and the fix is minimal. LGTM from my side.
Summary
When
_register_decorated_toolwraps a@tool-decorated method into a bound closure, it manually assigned only__name__and__doc__. This left__qualname__,__annotations__, and__wrapped__with incorrect or missing values on the resulting bound method.Fixes #7569
Problem
Solution
Replace the two manual attribute assignments with
functools.wraps, which is the standard Python idiom for wrapping functions and preserves all relevant metadata in a single call. Applied to both theasyncand sync branches ofmake_bound_method.Type of change
Checklist
./scripts/format.shand./scripts/validate.sh)Duplicate and AI-Generated PR Check