Skip to content

Commit

Permalink
.Net Agents - Emit streaming function call content for assistant agent (
Browse files Browse the repository at this point in the history
#9359)

### 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.
-->

Expose `StreamingFunctionCallUpdateContent` for streaming output of
`OpenAIAssistantAgent`

### Description
<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

@matthewbolanos identified assistant streaming wasn't aligned with
chat-completion in providing a message with
`StreamingFunctionCallUpdateContent` for a function-call.

### 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 😄
  • Loading branch information
crickman authored Oct 21, 2024
1 parent 656159e commit f2df866
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 12 deletions.
6 changes: 6 additions & 0 deletions dotnet/samples/Concepts/Agents/ChatCompletion_Streaming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ private async Task InvokeAgentAsync(ChatCompletionAgent agent, ChatHistory chat,
{
if (string.IsNullOrEmpty(response.Content))
{
StreamingFunctionCallUpdateContent? functionCall = response.Items.OfType<StreamingFunctionCallUpdateContent>().SingleOrDefault();
if (!string.IsNullOrEmpty(functionCall?.Name))
{
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {functionCall.Name}");
}

continue;
}

Expand Down
10 changes: 8 additions & 2 deletions dotnet/samples/Concepts/Agents/OpenAIAssistant_Streaming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ await OpenAIAssistantAgent.CreateAsync(
string threadId = await agent.CreateThreadAsync(new OpenAIThreadCreationOptions { Metadata = AssistantSampleMetadata });

// Respond to user input
await InvokeAgentAsync(agent, threadId, "What is the special soup?");
await InvokeAgentAsync(agent, threadId, "What is the special drink?");
await InvokeAgentAsync(agent, threadId, "What is the special soup and its price?");
await InvokeAgentAsync(agent, threadId, "What is the special drink and its price?");

// Output the entire chat history
await DisplayChatHistoryAsync(agent, threadId);
Expand Down Expand Up @@ -120,6 +120,12 @@ private async Task InvokeAgentAsync(OpenAIAssistantAgent agent, string threadId,
{
if (string.IsNullOrEmpty(response.Content))
{
StreamingFunctionCallUpdateContent? functionCall = response.Items.OfType<StreamingFunctionCallUpdateContent>().SingleOrDefault();
if (functionCall != null)
{
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {functionCall.Name}");
}

continue;
}

Expand Down
4 changes: 2 additions & 2 deletions dotnet/samples/GettingStartedWithAgents/Step08_Assistant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ await OpenAIAssistantAgent.CreateAsync(
try
{
await InvokeAgentAsync("Hello");
await InvokeAgentAsync("What is the special soup?");
await InvokeAgentAsync("What is the special drink?");
await InvokeAgentAsync("What is the special soup and its price?");
await InvokeAgentAsync("What is the special drink and its price?");
await InvokeAgentAsync("Thank you");
}
finally
Expand Down
26 changes: 18 additions & 8 deletions dotnet/src/Agents/OpenAI/Internal/AssistantThreadActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,15 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamin
{
yield return toolContent;
}
else
{
yield return
new StreamingChatMessageContent(AuthorRole.Assistant, null)
{
AuthorName = agent.Name,
Items = [new StreamingFunctionCallUpdateContent(detailsUpdate.ToolCallId, detailsUpdate.FunctionName, detailsUpdate.FunctionArguments)]
};
}
}
else if (update is RunStepUpdate stepUpdate)
{
Expand Down Expand Up @@ -493,15 +502,16 @@ await RetrieveMessageAsync(
{
foreach (RunStepToolCall toolCall in step.Details.ToolCalls)
{
switch (toolCall.ToolKind)
if (toolCall.ToolKind == RunStepToolCallKind.Function)
{
messages?.Add(GenerateFunctionResultContent(agent.GetName(), stepFunctionResults[step.Id], step));
stepFunctionResults.Remove(step.Id);
break;
}

if (toolCall.ToolKind == RunStepToolCallKind.CodeInterpreter)
{
case RunStepToolCallKind.CodeInterpreter:
messages?.Add(GenerateCodeInterpreterContent(agent.GetName(), toolCall.CodeInterpreterInput, step));
break;
case RunStepToolCallKind.Function:
messages?.Add(GenerateFunctionResultContent(agent.GetName(), stepFunctionResults[step.Id], step));
stepFunctionResults.Remove(step.Id);
break;
messages?.Add(GenerateCodeInterpreterContent(agent.GetName(), toolCall.CodeInterpreterInput, step));
}
}
}
Expand Down

0 comments on commit f2df866

Please sign in to comment.