@@ -19,9 +19,18 @@ public static class OpenAIChatHistoryExtensions
19
19
/// </summary>
20
20
/// <param name="chatHistory">Target chat history</param>
21
21
/// <param name="streamingMessageContents"><see cref="IAsyncEnumerator{T}"/> list of streaming message contents</param>
22
+ /// <param name="includeToolCalls">The tool call information from the processed message will be ignored (<c>false</c>) by default.</param>
23
+ /// <remarks>
24
+ /// Setting <c>removeToolCalls</c> to <c>false</c> should be only for manual tool calling scenarios, otherwise
25
+ /// may result in the error below. See <a href="https://github.com/microsoft/semantic-kernel/issues/9458">Issue 9458</a>
26
+ /// <code>An assistant message with 'tool_calls' must be followed by tool messages</code>
27
+ /// </remarks>
22
28
/// <returns>Returns the original streaming results with some message processing</returns>
23
29
[ Experimental ( "SKEXP0010" ) ]
24
- public static async IAsyncEnumerable < StreamingChatMessageContent > AddStreamingMessageAsync ( this ChatHistory chatHistory , IAsyncEnumerable < OpenAIStreamingChatMessageContent > streamingMessageContents )
30
+ public static async IAsyncEnumerable < StreamingChatMessageContent > AddStreamingMessageAsync (
31
+ this ChatHistory chatHistory ,
32
+ IAsyncEnumerable < OpenAIStreamingChatMessageContent > streamingMessageContents ,
33
+ bool includeToolCalls = false )
25
34
{
26
35
List < StreamingChatMessageContent > messageContents = [ ] ;
27
36
@@ -43,7 +52,10 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> AddStreamingMe
43
52
( contentBuilder ??= new ( ) ) . Append ( contentUpdate ) ;
44
53
}
45
54
46
- OpenAIFunctionToolCall . TrackStreamingToolingUpdate ( chatMessage . ToolCallUpdates , ref toolCallIdsByIndex , ref functionNamesByIndex , ref functionArgumentBuildersByIndex ) ;
55
+ if ( includeToolCalls )
56
+ {
57
+ OpenAIFunctionToolCall . TrackStreamingToolingUpdate ( chatMessage . ToolCallUpdates , ref toolCallIdsByIndex , ref functionNamesByIndex , ref functionArgumentBuildersByIndex ) ;
58
+ }
47
59
48
60
// Is always expected to have at least one chunk with the role provided from a streaming message
49
61
streamedRole ??= chatMessage . Role ;
@@ -62,7 +74,9 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> AddStreamingMe
62
74
role ,
63
75
contentBuilder ? . ToString ( ) ?? string . Empty ,
64
76
messageContents [ 0 ] . ModelId ! ,
65
- OpenAIFunctionToolCall . ConvertToolCallUpdatesToFunctionToolCalls ( ref toolCallIdsByIndex , ref functionNamesByIndex , ref functionArgumentBuildersByIndex ) ,
77
+ includeToolCalls
78
+ ? OpenAIFunctionToolCall . ConvertToolCallUpdatesToFunctionToolCalls ( ref toolCallIdsByIndex , ref functionNamesByIndex , ref functionArgumentBuildersByIndex )
79
+ : [ ] ,
66
80
metadata )
67
81
{ AuthorName = streamedName } ) ;
68
82
}
0 commit comments