Python: [BREAKING] Remove deprecated kwargs compatibility paths#4858
Python: [BREAKING] Remove deprecated kwargs compatibility paths#4858eavanvalkenburg wants to merge 4 commits intomicrosoft:mainfrom
Conversation
Remove the deprecated kwargs compatibility shims across core agents, clients, tools, middleware, and telemetry. Keep workflow kwargs behavior intact in this branch and follow up separately in microsoft#4850. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Removes deprecated **kwargs compatibility shims across the Python core agent/chat/tool stack, enforcing explicit runtime buckets (options, client_kwargs, function_invocation_kwargs) and FunctionInvocationContext for tool runtime context.
Changes:
- Remove legacy constructor/runtime
**kwargsfan-out paths in agents, chat clients, middleware, tools, and telemetry layers. - Enforce explicit tool runtime context via
FunctionInvocationContext(reject unexpected runtime kwargs inFunctionTool.invoke()). - Update and simplify tests to reflect the explicit APIs; delete legacy kwargs propagation coverage.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| python/packages/core/tests/core/test_tools.py | Updates tool invocation tests to assert runtime kwargs are rejected and ctx-based flow is required. |
| python/packages/core/tests/core/test_middleware_with_chat.py | Updates chat middleware tests to use context.options and explicit options={...} calls. |
| python/packages/core/tests/core/test_middleware_with_agent.py | Updates agent/function middleware tests to use function_invocation_kwargs and options. |
| python/packages/core/tests/core/test_kwargs_propagation_to_ai_function.py | Removes legacy coverage for kwargs propagation into tool **kwargs. |
| python/packages/core/tests/core/test_function_invocation_logic.py | Updates function-invocation tests to pass tools/tool_choice via options and session via client_kwargs. |
| python/packages/core/tests/core/test_clients.py | Changes BaseChatClient constructor test to expect TypeError for direct legacy kwargs. |
| python/packages/core/tests/core/test_agents.py | Changes Agent constructor test to expect TypeError for direct legacy kwargs; updates option plumbing expectations. |
| python/packages/core/agent_framework/observability.py | Updates telemetry layers to accept/forward explicit client_kwargs and function_invocation_kwargs (no **kwargs). |
| python/packages/core/agent_framework/_workflows/_agent_executor.py | Adds typing casts for new run signatures while continuing to pass workflow run kwargs into agent execution. |
| python/packages/core/agent_framework/_tools.py | Removes legacy runtime kwargs injection; enforces ctx-based runtime flow; tightens invoke() kwarg handling. |
| python/packages/core/agent_framework/_middleware.py | Updates middleware layers/signatures for explicit runtime buckets; adds run-level tools plumbing. |
| python/packages/core/agent_framework/_mcp.py | Updates MCP callback to pass model settings via options dict instead of direct kwargs. |
| python/packages/core/agent_framework/_clients.py | Removes legacy constructor kwargs merge; updates get_response signatures to explicit runtime buckets. |
| python/packages/core/agent_framework/_agents.py | Removes run(**kwargs) and constructor kwargs merge; adds explicit additional_properties and middleware plumbing. |
Comments suppressed due to low confidence (2)
python/packages/core/agent_framework/_workflows/_agent_executor.py:362
- AgentExecutor still forwards
**run_kwargsinto agent.run(). After this PR removesrun(**kwargs)compatibility, any workflow-level kwargs stored under WORKFLOW_RUN_KWARGS_KEY (e.g., custom_data / arbitrary values intended for tool context) will now raise TypeError at runtime. Since _prepare_agent_run_args already merges these values into options["additional_function_arguments"], run_kwargs should be filtered down to only explicit agent.run parameters (or cleared) before spreading into run().
run_kwargs, options = self._prepare_agent_run_args(ctx.get_state(WORKFLOW_RUN_KWARGS_KEY, {}))
run_agent = cast(Callable[..., Awaitable[AgentResponse[Any]]], self._agent.run)
response = await run_agent(
self._cache,
stream=False,
session=self._session,
options=options,
**run_kwargs,
)
python/packages/core/agent_framework/_workflows/_agent_executor.py:394
- Same issue in the streaming path: spreading
**run_kwargsinto agent.run(stream=True, ...) will now fail for workflow-provided arbitrary kwargs after removal ofrun(**kwargs)compatibility. Filter/clear run_kwargs (keeping only explicit agent.run parameters) and rely on options["additional_function_arguments"] / function_invocation_kwargs for propagating workflow runtime data.
run_agent_stream = cast(Callable[..., ResponseStream[AgentResponseUpdate, AgentResponse[Any]]], self._agent.run)
stream = run_agent_stream(
self._cache,
stream=True,
session=self._session,
options=options,
**run_kwargs,
)
eavanvalkenburg
left a comment
There was a problem hiding this comment.
Automated Code Review
Reviewers: 4 | Confidence: 83%
✗ Correctness
This PR removes deprecated
**kwargspatterns across the agent framework, replacing them with explicitfunction_invocation_kwargsandclient_kwargsparameters. The changes are internally consistent and tests are properly updated. One concrete bug: inChatMiddlewareLayer.get_response(),context_kwargsis copied fromeffective_client_kwargsbeforemiddlewareis popped, so amiddlewarekey inclient_kwargswould leak intocontext.kwargsand eventually downstreamclient_kwargs/_inner_get_response(). The old code popped middleware before constructing context kwargs. Additionally, removing theVAR_KEYWORDcontinuein_discover_injected_parametersintroduces a theoretical edge case where**ctxwithout annotation on a tool with explicitinput_modelcould be misidentified as a context parameter.
✓ Security Reliability
This PR removes deprecated
**kwargspass-through patterns across the agent/client/tool APIs, replacing them with explicit named parameters (function_invocation_kwargs,client_kwargs,tool_call_id). This is a positive security change: it eliminates an injection vector where arbitrary keyword arguments could leak into tool invocations, client calls, or middleware contexts. The main concerns are: (1) the_mcp.pysampling callback useschat_client: Anycast to bypass type checking, which silently hides signature mismatches and could cause runtime errors; (2) exception messages in_tools.pyinclude user-controlled parameter names which is a minor info-leak concern but acceptable for developer-facing errors; (3) the_agent_executor.pyintroducescast(Callable[...], self._agent.run)which bypasses type safety unnecessarily. No blocking security issues found.
✓ Test Coverage
This PR removes deprecated **kwargs patterns, replacing them with explicit parameters (function_invocation_kwargs, client_kwargs, tool_call_id). Test updates are mostly consistent with the code changes—deprecation-warning tests are replaced with TypeError-rejection tests, and middleware tests are updated to use the new explicit parameter style. However, the complete deletion of test_kwargs_propagation_to_ai_function.py removes the only end-to-end integration test verifying clean separation of function_invocation_kwargs vs client_kwargs through the full Agent → Client → Tool pipeline. Additionally, the MCP sampling_callback calling-convention change (positional kwargs to options dict) has no test verifying the new argument format, and the new AgentContext.tools attribute has no middleware-level test coverage.
✗ Design Approach
The PR cleanly removes the deprecated
**kwargsforwarding paths throughout the agent/client/tool stack and replaces them with explicitfunction_invocation_kwargs/client_kwargs/optionsparameters. The intent and scope are correct. There is one concrete regression introduced by the refactoring: inChatMiddlewareLayer.get_response,context_kwargsis now constructed fromeffective_client_kwargsbeforemiddlewareis popped from that dict. In the old code theChatContext.kwargsdict was built after the pop ({**effective_client_kwargs, **kwargs}whereeffective_client_kwargsalready hadmiddlewareremoved). In the new code anymiddlewarekey present inclient_kwargssurvives intocontext_kwargs, then gets forwarded by_middleware_handleras part ofclient_kwargsto the next layer, where downstream code pops and re-applies it — resulting in double middleware application. A secondary concern is the_mcp.pyfix usingchat_client: Any = self.client/response: Any = ...to silence a type-checker complaint;cast(SupportsChatGetResponse[Any], self.client)would constrain the escape to the minimum necessary. Finally,AgentContext.kwargsis kept as a public field but is now always{}becausekwargs=kwargsis no longer passed at construction; existing middleware that readscontext.kwargsto observe runtime parameters will silently see an empty dict with no deprecation warning.
Automated review by eavanvalkenburg's agents
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Motivation and Context
PR #4581 introduced explicit runtime buckets such as
additional_properties,client_kwargs, andfunction_invocation_kwargs, but it intentionally left deprecatedkwargs-based compatibility paths in place.This change removes those deprecated paths before more code depends on them again. It is a breaking change because callers that still rely on legacy constructor kwargs, direct runtime
run(**kwargs)/get_response(**kwargs)compatibility, or toolinvoke(**kwargs)runtime injection now need to move to the explicit APIs.Workflow
run(..., custom_data=...)behavior remains intentionally unchanged in this branch and is tracked separately in #4850.Description
This PR removes the remaining deprecated kwargs compatibility shims from the Python core stack.
BaseAgentandBaseChatClient, leavingadditional_propertiesas the explicit metadata bucket.options,client_kwargs, andfunction_invocation_kwargs.**kwargs; tool runtime context must now flow throughFunctionInvocationContext.Contribution Checklist