Repository navigation
Description
Describe the bug
KernelFunctionSelectionStrategy and KernelFunctionTerminationStrategy (python/semantic_kernel/agents/strategies) both declare a default for result_parser that cannot be called the way the strategy calls it. The default is a zero-argument lambda, but select_agent and should_agent_terminate call self.result_parser(result) with one argument. If you do not pass your own result_parser, the strategy always fails with a TypeError.
Selection strategy:
result_parser: Callable[..., str] = Field(default_factory=lambda: (lambda: ""))
...
agent_name = self.result_parser(result)Termination strategy:
result_parser: Callable[..., bool] = Field(default_factory=lambda: (lambda: True))
...
result_parsed = self.result_parser(result)To Reproduce
Run against current main (5b4a326):
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.agents.strategies import KernelFunctionSelectionStrategy, KernelFunctionTerminationStrategy
from semantic_kernel.functions import kernel_function
class P:
@kernel_function(name="pick")
def pick(self) -> str:
return "B"
@kernel_function(name="stop")
def stop(self) -> str:
return "true"
class A:
def __init__(self, n):
self.name = n
self.id = n
k = Kernel()
k.add_plugin(P(), "p")
async def main():
sel = KernelFunctionSelectionStrategy(function=k.get_function("p", "pick"), kernel=k)
try:
await sel.select_agent([A("A"), A("B")], [])
except Exception as e:
print("SEL", type(e).__name__, e)
term = KernelFunctionTerminationStrategy(function=k.get_function("p", "stop"), kernel=k)
try:
await term.should_agent_terminate(A("A"), [])
except Exception as e:
print("TERM", type(e).__name__, e)
asyncio.run(main())Output:
SEL TypeError KernelFunctionSelectionStrategy.<lambda>.<locals>.<lambda>() takes 0 positional arguments but 1 was given
TERM TypeError KernelFunctionTerminationStrategy.<lambda>.<locals>.<lambda>() takes 0 positional arguments but 1 was given
Expected behavior
Constructing either strategy without a result_parser should work, or the field should be required. Today the field looks optional but is not.
Proposed fix
I would keep the field optional and give it a default that takes the function result:
- Selection: return
str(result).strip(), so a function that returns an agent name selects that agent. - Termination: return
str(result).strip().lower() == "true", so a function that returnstrueends the chat.
I picked this over making result_parser a required field because it does not break any caller that passes its own parser, and the behavior is easy to predict. For termination I did not keep "always return True" as the default, because that would stop the chat after the first check regardless of the function output, which makes the kernel function pointless.
I have a fix with tests ready and can open a PR if this direction is acceptable.
Platform
- Language: Python
- Source: main branch (5b4a326)
- OS: Windows, Python 3.13
Activity
Li-john1021 commentedon Oct 14, 2026
Hi! I'd like to work on this if nobody is already on it.
I plan a small fix so the default
result_parseraccepts the function result (selection:str(result).strip(); termination: treat"true"as terminate), plus regression tests for the current TypeError. Happy to adjust if maintainers prefer a different default.Please assign me (Li-john1021) if that sounds alright — and sorry if I stepped on anyone who was already preparing a PR.