Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ async def get_chat_message_contents(
Returns:
A list of chat message contents representing the response(s) from the LLM.
"""
from semantic_kernel.connectors.ai.function_calling_utils import (
merge_function_results,
)
from semantic_kernel.connectors.ai.function_calling_utils import merge_function_results

# Create a copy of the settings to avoid modifying the original settings
settings = copy.deepcopy(settings)
Expand Down Expand Up @@ -210,9 +208,7 @@ async def get_streaming_chat_message_contents(
Yields:
A stream representing the response(s) from the LLM.
"""
from semantic_kernel.connectors.ai.function_calling_utils import (
merge_streaming_function_results,
)
from semantic_kernel.connectors.ai.function_calling_utils import merge_streaming_function_results

# Create a copy of the settings to avoid modifying the original settings
settings = copy.deepcopy(settings)
Expand Down Expand Up @@ -316,6 +312,13 @@ async def get_streaming_chat_message_contents(

if any(result.terminate for result in results if result is not None):
break
else:
# Do a final call, without function calling when the max has been reached.
self._reset_function_choice_settings(settings)
async for streaming_chat_message_contents in self._inner_get_streaming_chat_message_contents(
chat_history, settings

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

In the final non function calling call, _inner_get_streaming_chat_message_contents is invoked without passing function_invoke_attempt, so derived connectors will default it to 0. That can produce duplicate function_invoke_attempt values across attempts and may break consumers that group, dedupe, or combine streaming messages by attempt. Pass an explicit attempt index for this final call, for example settings.function_choice_behavior.maximum_auto_invoke_attempts.

Suggested change
chat_history, settings
chat_history,
settings,
function_invoke_attempt=settings.function_choice_behavior.maximum_auto_invoke_attempts,

Copilot uses AI. Check for mistakes.
):
yield streaming_chat_message_contents
Comment on lines +315 to +321

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

This adds new control flow for streaming auto invoke exhaustion (the for ... else final call after maximum_auto_invoke_attempts). Please add a unit test that exercises this path and asserts that a final model invocation happens after the last tool call and that function calling is disabled for that final invocation (via _reset_function_choice_settings).

Copilot uses AI. Check for mistakes.

async def get_streaming_chat_message_content(
self,
Expand Down
Loading