fix: forward callbacks/config through static-args tool wrapper#922
Open
edis-uipath wants to merge 1 commit into
Open
fix: forward callbacks/config through static-args tool wrapper#922edis-uipath wants to merge 1 commit into
edis-uipath wants to merge 1 commit into
Conversation
The static-args wrapper replaced a tool's coroutine/func with a **kwargs-only callable, which hid the original signature from StructuredTool._arun/_run. Those methods inspect the callable signature to decide whether to forward the child `callbacks` and the runnable `config`, so a wrapped tool that declares either stopped receiving them. Use functools.wraps so inspect.signature sees through to the original callable (restoring detection), and forward the injected callbacks/config as-is, bypassing apply_static_args whose serialization sanitization would mangle the callback manager / config objects. Static-arg injection still applies only to the model-supplied args. Adds a test invoking a config/callbacks-declaring coroutine through ainvoke and asserting both arrive alongside the injected static value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the static-args tool wrapper so LangChain can still detect and forward runtime-injected kwargs (callbacks and the RunnableConfig-typed param) after wrapping a tool’s coroutine/func.
Changes:
- Add
functools.wrapsaround the wrapper callables soinspect.signatureremains transparent to LangChain. - Introduce
_runtime_passthrough_keys()and ensure runtime-injected kwargs bypassapply_static_args. - Add a regression test asserting
config/callbacksreach a wrapped coroutine that explicitly declares them.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/uipath_langchain/agent/tools/static_args.py |
Preserve callable signatures via wraps and forward runtime-injected kwargs outside static-arg merging. |
tests/agent/tools/test_wrap_static_args.py |
Add coverage ensuring wrapped tools still receive RunnableConfig and callbacks. |
Comment on lines
+361
to
+367
| keys: set[str] = set() | ||
| if "callbacks" in signature(target).parameters: | ||
| keys.add("callbacks") | ||
| config_param = _get_runnable_config_param(target) | ||
| if config_param: | ||
| keys.add(config_param) | ||
| return keys |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Addresses the Copilot review comment on #921 (discussion).
wrap_tool_with_static_argsreplaces a tool'scoroutine/funcwith a**kwargs-only callable.StructuredTool._arun/_run(andBaseUiPathStructuredTool's override) decide whether to forward the childcallbacksand the runnableconfiginto the callable by inspecting its signature (signature(self.coroutine).parameters.get("callbacks")and_get_runnable_config_param(...)). A**kwargs-only wrapper hides those, so a wrapped tool that declaresconfig/callbackswould stop receiving them.Fix
@functools.wraps(_coroutine)/@functools.wraps(_func)soinspect.signaturesees through to the original callable — restoring LangChain's detection._runtime_passthrough_keyshelper computes which keys LangChain injects (callbacks+ theRunnableConfig-typed param) from the original signature.apply_static_args— whosesanitize_dict_for_serializationwould otherwise mangle a live callback-manager / config object. Static-arg injection still applies only to the model-supplied args.Impact / scope
No behavior change for any current tool: every wrapped coroutine today is
**kwargs-only (integration / process / escalation / extraction / MCP / A2A) or reads config from thevar_child_runnable_configcontextvar (analyze_files), so_runtime_passthrough_keysis empty and the path is identical to before. This is forward-looking hardening so a future wrapped coroutine that declaresconfig/callbackskeeps working.Tests
New
test_wrapper_forwards_config_and_callbacks_to_coroutine: a coroutine declaringconfig: RunnableConfig+callbacks, invoked viaainvoke, asserts the static value is injected and bothconfigandcallbacksarrive. (It errors without thefunctools.wrapsfix, so it's a real guard.)Verification:
ruff check/formatclean,mypyclean,pytest tests/agent/tools/→ 637 passed.🤖 Generated with Claude Code