Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into feature/postgres-me…
Browse files Browse the repository at this point in the history
…mory
  • Loading branch information
lossyrob committed Oct 3, 2024
2 parents 23faeff + 329d572 commit b93db84
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 15 deletions.
70 changes: 55 additions & 15 deletions dotnet/samples/Concepts/Agents/OpenAIAssistant_Streaming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,24 @@ namespace Agents;
/// </summary>
public class OpenAIAssistant_Streaming(ITestOutputHelper output) : BaseAgentsTest(output)
{
private const string ParrotName = "Parrot";
private const string ParrotInstructions = "Repeat the user message in the voice of a pirate and then end with a parrot sound.";

[Fact]
public async Task UseStreamingAssistantAgentAsync()
{
const string AgentName = "Parrot";
const string AgentInstructions = "Repeat the user message in the voice of a pirate and then end with a parrot sound.";

// Define the agent
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
kernel: new(),
clientProvider: this.GetClientProvider(),
definition: new OpenAIAssistantDefinition(this.Model)
{
Instructions = ParrotInstructions,
Name = ParrotName,
Metadata = AssistantSampleMetadata,
});
await OpenAIAssistantAgent.CreateAsync(
kernel: new(),
clientProvider: this.GetClientProvider(),
definition: new OpenAIAssistantDefinition(this.Model)
{
Instructions = AgentInstructions,
Name = AgentName,
EnableCodeInterpreter = true,
Metadata = AssistantSampleMetadata,
});

// Create a thread for the agent conversation.
string threadId = await agent.CreateThreadAsync(new OpenAIThreadCreationOptions { Metadata = AssistantSampleMetadata });
Expand All @@ -44,7 +45,8 @@ await OpenAIAssistantAgent.CreateAsync(
[Fact]
public async Task UseStreamingAssistantAgentWithPluginAsync()
{
const string MenuInstructions = "Answer questions about the menu.";
const string AgentName = "Host";
const string AgentInstructions = "Answer questions about the menu.";

// Define the agent
OpenAIAssistantAgent agent =
Expand All @@ -53,8 +55,8 @@ await OpenAIAssistantAgent.CreateAsync(
clientProvider: this.GetClientProvider(),
definition: new OpenAIAssistantDefinition(this.Model)
{
Instructions = MenuInstructions,
Name = "Host",
Instructions = AgentInstructions,
Name = AgentName,
Metadata = AssistantSampleMetadata,
});

Expand All @@ -73,6 +75,36 @@ await OpenAIAssistantAgent.CreateAsync(
await DisplayChatHistoryAsync(agent, threadId);
}

[Fact]
public async Task UseStreamingAssistantWithCodeInterpreterAsync()
{
const string AgentName = "MathGuy";
const string AgentInstructions = "Solve math problems with code.";

// Define the agent
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
kernel: new(),
clientProvider: this.GetClientProvider(),
definition: new OpenAIAssistantDefinition(this.Model)
{
Instructions = AgentInstructions,
Name = AgentName,
EnableCodeInterpreter = true,
Metadata = AssistantSampleMetadata,
});

// Create a thread for the agent conversation.
string threadId = await agent.CreateThreadAsync(new OpenAIThreadCreationOptions { Metadata = AssistantSampleMetadata });

// Respond to user input
await InvokeAgentAsync(agent, threadId, "Is 191 a prime number?");
await InvokeAgentAsync(agent, threadId, "Determine the values in the Fibonacci sequence that that are less then the value of 101");

// Output the entire chat history
await DisplayChatHistoryAsync(agent, threadId);
}

// Local function to invoke agent and display the conversation messages.
private async Task InvokeAgentAsync(OpenAIAssistantAgent agent, string threadId, string input)
{
Expand All @@ -83,13 +115,21 @@ private async Task InvokeAgentAsync(OpenAIAssistantAgent agent, string threadId,
ChatHistory history = [];

bool isFirst = false;
bool isCode = false;
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(threadId, messages: history))
{
if (string.IsNullOrEmpty(response.Content))
{
continue;
}

// Differentiate between assistant and tool messages
if (isCode != (response.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false))
{
isFirst = false;
isCode = !isCode;
}

if (!isFirst)
{
Console.WriteLine($"\n# {response.Role} - {response.AuthorName ?? "*"}:");
Expand Down
39 changes: 39 additions & 0 deletions dotnet/src/Agents/OpenAI/Internal/AssistantThreadActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,14 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamin
break;
}
}
else if (update is RunStepDetailsUpdate detailsUpdate)
{
StreamingChatMessageContent? toolContent = GenerateStreamingCodeInterpreterContent(agent.GetName(), detailsUpdate);
if (toolContent != null)
{
yield return toolContent;
}
}
else if (update is RunStepUpdate stepUpdate)
{
switch (stepUpdate.UpdateKind)
Expand All @@ -416,6 +424,8 @@ public static async IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamin
case StreamingUpdateReason.RunStepCompleted:
currentStep = null;
break;
default:
break;
}
}
}
Expand Down Expand Up @@ -571,6 +581,35 @@ private static StreamingChatMessageContent GenerateStreamingMessageContent(strin
return content;
}

private static StreamingChatMessageContent? GenerateStreamingCodeInterpreterContent(string? assistantName, RunStepDetailsUpdate update)
{
StreamingChatMessageContent content =
new(AuthorRole.Assistant, content: null)
{
AuthorName = assistantName,
};

// Process text content
if (update.CodeInterpreterInput != null)
{
content.Items.Add(new StreamingTextContent(update.CodeInterpreterInput));
content.Metadata = new Dictionary<string, object?> { { OpenAIAssistantAgent.CodeInterpreterMetadataKey, true } };
}

if ((update.CodeInterpreterOutputs?.Count ?? 0) > 0)
{
foreach (var output in update.CodeInterpreterOutputs!)
{
if (output.ImageFileId != null)
{
content.Items.Add(new StreamingFileReferenceContent(output.ImageFileId));
}
}
}

return content.Items.Count > 0 ? content : null;
}

private static AnnotationContent GenerateAnnotationContent(TextAnnotation annotation)
{
string? fileId = null;
Expand Down

0 comments on commit b93db84

Please sign in to comment.