Skip to content

Python: Fix bool parameter coercion so string "false" is not silently treated as True#14163

Open
sohumt123 wants to merge 1 commit into
microsoft:mainfrom
sohumt123:fix-bool-string-coercion
Open

Python: Fix bool parameter coercion so string "false" is not silently treated as True#14163
sohumt123 wants to merge 1 commit into
microsoft:mainfrom
sohumt123:fix-bool-string-coercion

Conversation

@sohumt123

Copy link
Copy Markdown

Motivation and Context

When a kernel function declares a bool parameter and the incoming KernelArguments value is a string — which is common when an LLM tool call quotes booleans as JSON strings, when arguments flow through the template engine (which passes strings), or when values originate from env/CLI/form input — KernelFunctionFromMethod._parse_parameter falls through to the generic param_type(value) fallback. Since bool("false") is True for any non-empty string, enabled="false" silently runs the function with enabled=True. No error, no warning — the flag is simply inverted.

Repro on current main:

@kernel_function
def set_flag(enabled: bool) -> str:
    return f"enabled={enabled}"

func = kernel.add_function(plugin_name="test", function_name="set_flag", function=set_flag)
result = await kernel.invoke(func, KernelArguments(enabled="false"))
# result: "enabled=True"  <-- flag inverted

This is also a cross-SDK inconsistency: the .NET SDK marshals the same case correctly ("false" -> false via TypeConverter/bool.Parse semantics).

Description

Adds an explicit branch in _parse_parameter for param_type is bool with a string value, before the generic fallback:

  • "true" / "1" -> True, "false" / "0" -> False (case-insensitive, whitespace-stripped)
  • any other string raises FunctionExecutionException(f"Cannot parse string '{value}' as bool.") instead of silently returning True
  • non-string values (real bool, int) and all other parameter types keep the existing behavior

Tests added in test_kernel_function_from_method.py:

  • parametrized _parse_parameter coverage for "true"/"True"/"1"/"false"/"False"/"FALSE"/"0"/" false " plus non-string True/False/1/0 passthrough
  • an invalid-string case ("yes") asserting the raised FunctionExecutionException
  • an end-to-end kernel.invoke test showing enabled="false" now reaches the function as False

All of these fail on main without the fix (the end-to-end test gets enabled=True) and pass with it. uv run --frozen pytest tests/unit/functions tests/unit/kernel passes (301 tests, including the 50 in the touched test file), and ruff check, ruff format --check, and mypy are clean on the touched files.

Contribution Checklist

…o True

When a kernel function declares a bool parameter and the incoming
argument is a string (e.g. an LLM tool call that quotes booleans, or
values coming through the template engine), _parse_parameter fell
through to the generic param_type(value) fallback. bool("false") is
True for any non-empty string, so enabled="false" silently ran the
function with enabled=True.

Parse bool-typed string arguments explicitly: "true"/"1" -> True,
"false"/"0" -> False (case-insensitive, whitespace-stripped), and
raise FunctionExecutionException for unparseable strings. Non-string
values keep the existing behavior. This matches the .NET SDK, which
parses "false" as false.
Copilot AI review requested due to automatic review settings July 17, 2026 17:25
@sohumt123
sohumt123 requested a review from a team as a code owner July 17, 2026 17:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Python kernel function argument coercion so string booleans (e.g., "false") are parsed to the correct bool value instead of falling back to Python’s bool("false") == True behavior, aligning with expected tool-call/template argument flows and cross-SDK behavior.

Changes:

  • Add explicit string-to-bool parsing in KernelFunctionFromMethod._parse_parameter for "true"/"1" and "false"/"0" (case-insensitive, whitespace-trimmed), raising on invalid strings.
  • Add unit coverage for _parse_parameter(..., bool) with common string/non-string inputs and invalid string handling.
  • Add an end-to-end kernel.invoke test verifying "false" and "true" string arguments reach the function as False/True.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
python/semantic_kernel/functions/kernel_function_from_method.py Adds explicit string-to-bool parsing branch to avoid incorrect coercion from non-empty strings.
python/tests/unit/functions/test_kernel_function_from_method.py Adds unit + end-to-end tests to verify correct boolean coercion and invalid-string error behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


def test_parse_invalid_bool_string_raises_exception(get_custom_type_function_pydantic):
func = get_custom_type_function_pydantic
with pytest.raises(FunctionExecutionException, match=r"Cannot parse string 'yes' as bool."):
@sohumt123

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@rogerbarreto rogerbarreto added the python Pull requests for the Python Semantic Kernel label Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants