From 8b84dc0decfaf319f57ca8ea9fc881a945ff212c Mon Sep 17 00:00:00 2001 From: Sohum Trivedi Date: Fri, 17 Jul 2026 10:16:22 -0700 Subject: [PATCH] Python: fix FunctionResult.__str__ rendering falsy values (0, False, 0.0) as empty string FunctionResult.__str__ used a truthiness check (if self.value:) where a None-check was intended, so kernel functions returning falsy-but-meaningful scalars (0, 0.0, False) rendered as an empty string when interpolated into a prompt template, silently corrupting the prompt sent to the model. Change the check to 'if self.value is not None:' and add explicit guards for empty list/dict values so they still render as an empty string (an empty dict would otherwise raise FunctionResultError when indexing). Adds unit tests for 0, 0.0, False, '', [], {} and a KernelPromptTemplate render test covering falsy function results. --- .../functions/function_result.py | 6 ++++- .../unit/functions/test_function_result.py | 19 +++++++++++++++ .../test_kernel_prompt_template.py | 24 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/python/semantic_kernel/functions/function_result.py b/python/semantic_kernel/functions/function_result.py index 1d3dd0c29f59..38e988846294 100644 --- a/python/semantic_kernel/functions/function_result.py +++ b/python/semantic_kernel/functions/function_result.py @@ -37,9 +37,11 @@ class FunctionResult(KernelBaseModel): def __str__(self) -> str: """Get the string representation of the result.""" - if self.value: + if self.value is not None: try: if isinstance(self.value, list): + if not self.value: + return "" return ( str(self.value[0]) if isinstance(self.value[0], KernelContent) @@ -48,6 +50,8 @@ def __str__(self) -> str: if isinstance(self.value, dict): # TODO (eavanvalkenburg): remove this once function result doesn't include input args # This is so an integration test can pass. + if not self.value: + return "" return str(list(self.value.values())[-1]) return str(self.value) except Exception as e: diff --git a/python/tests/unit/functions/test_function_result.py b/python/tests/unit/functions/test_function_result.py index a8f686e9648b..7f29e82b548f 100644 --- a/python/tests/unit/functions/test_function_result.py +++ b/python/tests/unit/functions/test_function_result.py @@ -63,6 +63,25 @@ def test_function_result_str_empty_value(): assert str(result) == "" +@pytest.mark.parametrize( + ("value", "expected"), + [ + (0, "0"), + (0.0, "0.0"), + (False, "False"), + ("", ""), + ([], ""), + ({}, ""), + ], +) +def test_function_result_str_with_falsy_value(value, expected): + result = FunctionResult( + function=KernelFunctionMetadata(name="test_function", is_prompt=False, is_asynchronous=False), + value=value, + ) + assert str(result) == expected + + def test_function_result_str_with_conversion_error(): class Unconvertible: def __str__(self): diff --git a/python/tests/unit/prompt_template/test_kernel_prompt_template.py b/python/tests/unit/prompt_template/test_kernel_prompt_template.py index 6d8b1a1b2bf0..0bf2367a5e7f 100644 --- a/python/tests/unit/prompt_template/test_kernel_prompt_template.py +++ b/python/tests/unit/prompt_template/test_kernel_prompt_template.py @@ -121,6 +121,30 @@ async def my_function(myVar: str) -> str: assert result == "foo-BAR-baz" +async def test_it_renders_code_with_falsy_results(kernel: Kernel): + arguments = KernelArguments() + + @kernel_function(name="subtract") + def subtract(a: int, b: int) -> int: + return a - b + + @kernel_function(name="is_even") + def is_even(a: int) -> bool: + return a % 2 == 0 + + kernel.add_function("math", KernelFunction.from_method(subtract, "math")) + kernel.add_function("math", KernelFunction.from_method(is_even, "math")) + + arguments["x"] = 5 + arguments["y"] = 5 + arguments["z"] = 3 + template = "The result is: {{math.subtract a=$x b=$y}} and even={{math.is_even a=$z}}" + target = create_kernel_prompt_template(template, allow_dangerously_set_content=True) + result = await target.render(kernel, arguments) + + assert result == "The result is: 0 and even=False" + + async def test_it_renders_code_error(kernel: Kernel): arguments = KernelArguments()