Python: preserve explicit null arguments in auto function calling#7108
Open
he-yufeng wants to merge 1 commit into
Open
Python: preserve explicit null arguments in auto function calling#7108he-yufeng wants to merge 1 commit into
he-yufeng wants to merge 1 commit into
Conversation
FunctionTool.invoke dumped validated arguments with model_dump(exclude_none=True), which strips any argument the model set to null. A required nullable parameter (e.g. unit: Literal["C","F"] | None) that the model deliberately sets to null was therefore dropped, and the function failed to invoke on the missing argument. Use exclude_unset instead: keep the arguments the model actually provided (null included) and omit only the ones it left out, so the function's own defaults still apply. Because the input model is generated from the function signature, its field defaults match the signature defaults, so omitted optionals are unchanged. Fixes microsoft#5934 Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a Python tool-invocation edge case where explicitly-provided null arguments were being dropped during argument validation, which can break invocation of required-but-nullable parameters in auto function calling.
Changes:
- Switch
FunctionTool.invoke()argument dumping fromexclude_none=Truetoexclude_unset=Trueto preserve explicitnullvalues while still omitting truly-omitted fields. - Add regression tests to confirm explicit
Noneis preserved for required nullable parameters and omitted optionals still use function defaults.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| python/packages/core/agent_framework/_tools.py | Updates FunctionTool.invoke() argument dumping behavior to preserve explicit nulls. |
| python/packages/core/tests/core/test_tools.py | Adds regression tests for explicit-null preservation and omitted-optional default behavior. |
Comment on lines
+658
to
+662
| # exclude_unset (not exclude_none): keep arguments the model | ||
| # explicitly provided even when their value is null, and drop | ||
| # only the ones it left out, so the function's own defaults | ||
| # apply. Excluding null instead would strip a required nullable | ||
| # parameter the model deliberately set to null, failing the |
Comment on lines
+154
to
+158
| async def test_invoke_preserves_explicit_null_argument(): | ||
| """A required nullable argument the model sets to null must reach the function. | ||
|
|
||
| Regression for #5934: exclude_none dropped the explicit null, so the required | ||
| ``unit`` went missing and the invocation failed. |
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.
Description
Fixes #5934.
FunctionTool.invokedumped the validated arguments withmodel_dump(exclude_none=True), which strips any argument whose value isnull. When the model deliberately sets a required nullable parameter tonull— e.g.unit: Literal["C", "F"] | Nonewith a description telling the model to set it tonullwhen the user gave no unit — that argument was dropped, and the function then failed to invoke on the missing required argument.The fix uses
exclude_unset=Trueinstead: keep the arguments the model actually provided (an explicitnullincluded) and omit only the ones it left out, so the function's own defaults still apply. Because the tool's input model is generated from the function signature, its field defaults match the signature defaults, so omitted optionals behave exactly as before — only explicitly-provided nulls are now preserved.Changed both the mapping path (the auto-function-calling path from the model) and the
BaseModelpath for consistency.Behavior
For a required nullable parameter the model sets to
null:An omitted optional argument still falls back to the function's own default (unchanged).
Tests
Adds
test_invoke_preserves_explicit_null_argument(the #5934 repro, fails against the old behavior) andtest_invoke_omitted_optional_uses_function_default(guards that omitted optionals still use the function default).