Skip to content

Commit d25f915

Browse files
authored
.Net Agents - Fix OpenAIAssistant and AzureAIAgent function-call streaming (#12205)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> `StreamingFunctionCallUpdateContent` not being provided by `OpenAIAssistantAgent` and `AzureAIAgent` ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> The lack of `StreamingFunctionCallUpdateContent` interferes with the ability to display progress information. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [X] The code builds clean without any errors or warnings - [X] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [X] All unit tests pass, and I have added new tests where possible - [X] I didn't break anyone 😄
1 parent da74476 commit d25f915

File tree

5 files changed

+34
-18
lines changed

5 files changed

+34
-18
lines changed

dotnet/samples/Concepts/Agents/AzureAIAgent_Streaming.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@ Task OnNewMessage(ChatMessageContent message)
138138
if (string.IsNullOrEmpty(response.Content))
139139
{
140140
StreamingFunctionCallUpdateContent? functionCall = response.Items.OfType<StreamingFunctionCallUpdateContent>().SingleOrDefault();
141-
if (functionCall != null)
141+
if (functionCall?.Name != null)
142142
{
143-
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {functionCall.Name}");
143+
(string? pluginName, string functionName) = this.ParseFunctionName(functionCall.Name);
144+
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {$"{pluginName}." ?? string.Empty}{functionName}");
144145
}
145146

146147
continue;
@@ -187,11 +188,12 @@ public sealed class MenuPlugin
187188
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Too smart")]
188189
public string GetSpecials()
189190
{
190-
return @"
191-
Special Soup: Clam Chowder
192-
Special Salad: Cobb Salad
193-
Special Drink: Chai Tea
194-
";
191+
return
192+
"""
193+
Special Soup: Clam Chowder
194+
Special Salad: Cobb Salad
195+
Special Drink: Chai Tea
196+
""";
195197
}
196198

197199
[KernelFunction, Description("Provides the price of the requested menu item.")]

dotnet/samples/Concepts/Agents/OpenAIAssistant_Streaming.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,10 @@ Task OnNewMessage(ChatMessageContent message)
112112
if (string.IsNullOrEmpty(response.Content))
113113
{
114114
StreamingFunctionCallUpdateContent? functionCall = response.Items.OfType<StreamingFunctionCallUpdateContent>().SingleOrDefault();
115-
if (functionCall != null)
115+
if (functionCall?.Name != null)
116116
{
117-
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {functionCall.Name}");
117+
(string? pluginName, string functionName) = this.ParseFunctionName(functionCall.Name);
118+
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {$"{pluginName}." ?? string.Empty}{functionName}");
118119
}
119120

120121
continue;
@@ -161,11 +162,12 @@ public sealed class MenuPlugin
161162
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Too smart")]
162163
public string GetSpecials()
163164
{
164-
return @"
165-
Special Soup: Clam Chowder
166-
Special Salad: Cobb Salad
167-
Special Drink: Chai Tea
168-
";
165+
return
166+
"""
167+
Special Soup: Clam Chowder
168+
Special Salad: Cobb Salad
169+
Special Drink: Chai Tea
170+
""";
169171
}
170172

171173
[KernelFunction, Description("Provides the price of the requested menu item.")]

dotnet/src/Agents/AzureAI/Internal/AgentThreadActions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,13 +421,14 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamin
421421
{
422422
yield return toolContent;
423423
}
424-
else if (detailsUpdate.FunctionOutput != null)
424+
else if (detailsUpdate.FunctionName != null || detailsUpdate.FunctionArguments != null)
425425
{
426426
yield return
427427
new StreamingChatMessageContent(AuthorRole.Assistant, null)
428428
{
429429
AuthorName = agent.Name,
430-
Items = [new StreamingFunctionCallUpdateContent(detailsUpdate.ToolCallId, detailsUpdate.FunctionName, detailsUpdate.FunctionArguments)]
430+
Items = [new StreamingFunctionCallUpdateContent(detailsUpdate.ToolCallId, detailsUpdate.FunctionName, detailsUpdate.FunctionArguments, detailsUpdate.ToolCallIndex ?? 0)],
431+
InnerContent = detailsUpdate,
431432
};
432433
}
433434
}

dotnet/src/Agents/OpenAI/Internal/AssistantThreadActions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,14 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamin
412412
{
413413
yield return toolContent;
414414
}
415-
else if (detailsUpdate.FunctionOutput != null)
415+
else if (detailsUpdate.FunctionName != null || detailsUpdate.FunctionArguments != null)
416416
{
417417
yield return
418418
new StreamingChatMessageContent(AuthorRole.Assistant, null)
419419
{
420420
AuthorName = agent.Name,
421-
Items = [new StreamingFunctionCallUpdateContent(detailsUpdate.ToolCallId, detailsUpdate.FunctionName, detailsUpdate.FunctionArguments)]
421+
Items = [new StreamingFunctionCallUpdateContent(detailsUpdate.ToolCallId, detailsUpdate.FunctionName, detailsUpdate.FunctionArguments, detailsUpdate.ToolCallIndex ?? 0)],
422+
InnerContent = detailsUpdate,
422423
};
423424
}
424425
}

dotnet/src/InternalUtilities/samples/AgentUtilities/BaseAgentsTest.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ public abstract class BaseAgentsTest(ITestOutputHelper output) : BaseTest(output
4848
{ SampleMetadataKey, bool.TrueString }
4949
});
5050

51+
protected (string? pluginName, string functionName) ParseFunctionName(string functionName)
52+
{
53+
string[] parts = functionName.Split("-", 2);
54+
if (parts.Length == 1)
55+
{
56+
return (null, parts[0]);
57+
}
58+
return (parts[0], parts[1]);
59+
}
60+
5161
/// <summary>
5262
/// Common method to write formatted agent chat content to the console.
5363
/// </summary>

0 commit comments

Comments
 (0)