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()