Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenHodgson committed Nov 14, 2024
1 parent b00fe7d commit 9354fdd
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 56 deletions.
27 changes: 16 additions & 11 deletions OpenAI-DotNet-Tests/TestFixture_03_Threads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public async Task Test_03_01_CreateRun()
}

[Test]
public async Task Test_03_03_01_CreateRun_Streaming()
public async Task Test_03_02_01_CreateRun_Streaming()
{
Assert.NotNull(OpenAIClient.ThreadsEndpoint);
var assistant = await OpenAIClient.AssistantsEndpoint.CreateAssistantAsync(
Expand Down Expand Up @@ -269,7 +269,6 @@ public async Task Test_03_03_01_CreateRun_Streaming()
break;
case RunStepResponse runStepEvent:
Assert.NotNull(runStepEvent);

switch (runStepEvent.Object)
{
case "thread.run.step.delta":
Expand All @@ -285,7 +284,6 @@ public async Task Test_03_03_01_CreateRun_Streaming()
break;
case MessageResponse messageEvent:
Assert.NotNull(messageEvent);

switch (messageEvent.Object)
{
case "thread.message.delta":
Expand Down Expand Up @@ -328,13 +326,14 @@ public async Task Test_03_03_01_CreateRun_Streaming()
}

[Test]
public async Task Test_03_03_02_CreateRun_Streaming_ToolCalls()
public async Task Test_03_02_02_CreateRun_Streaming_ToolCalls()
{
Assert.NotNull(OpenAIClient.ThreadsEndpoint);
var tools = new List<Tool>
{
Tool.GetOrCreateTool(typeof(WeatherService), nameof(WeatherService.GetCurrentWeatherAsync))
};
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null), "Expected all tool function arguments to be null");
var assistantRequest = new CreateAssistantRequest(tools: tools, instructions: "You are a helpful weather assistant. Use the appropriate unit based on geographical location.");
var assistant = await OpenAIClient.AssistantsEndpoint.CreateAssistantAsync(assistantRequest);
Assert.NotNull(assistant);
Expand Down Expand Up @@ -468,9 +467,9 @@ public async Task Test_04_02_CreateThreadAndRun_Streaming()
try
{
var run = await assistant.CreateThreadAndRunAsync("I need to solve the equation `3x + 11 = 14`. Can you help me?",
async @event =>
async streamEvent =>
{
Console.WriteLine(@event.ToJsonString());
Console.WriteLine(streamEvent.ToJsonString());
await Task.CompletedTask;
});
Assert.IsNotNull(run);
Expand Down Expand Up @@ -503,11 +502,11 @@ public async Task Test_04_02_CreateThreadAndRun_Streaming()
public async Task Test_04_03_CreateThreadAndRun_Streaming_ToolCalls()
{
Assert.NotNull(OpenAIClient.ThreadsEndpoint);

var tools = new List<Tool>
{
Tool.GetOrCreateTool(typeof(DateTimeUtility), nameof(DateTimeUtility.GetDateTime))
};
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null), "Expected all tool function arguments to be null");
var assistantRequest = new CreateAssistantRequest(
instructions: "You are a helpful assistant.",
tools: tools);
Expand All @@ -516,11 +515,13 @@ public async Task Test_04_03_CreateThreadAndRun_Streaming_ToolCalls()
ThreadResponse thread = null;
// check if any exceptions thrown in stream event handler
var exceptionThrown = false;
var hasInvokedCallback = false;

try
{
async Task StreamEventHandler(IServerSentEvent streamEvent)
{
hasInvokedCallback = true;
Console.WriteLine($"{streamEvent.ToJsonString()}");

try
Expand All @@ -536,8 +537,9 @@ async Task StreamEventHandler(IServerSentEvent streamEvent)
var toolOutputs = await assistant.GetToolOutputsAsync(runResponse);
var toolRun = await runResponse.SubmitToolOutputsAsync(toolOutputs, StreamEventHandler);
Assert.NotNull(toolRun);
Assert.IsTrue(toolRun.Status == RunStatus.Completed);
Assert.IsTrue(toolRun.Status == RunStatus.Completed, $"Failed to complete submit tool outputs! {toolRun.Status}");
}

break;
case Error errorResponse:
throw errorResponse.Exception ?? new Exception(errorResponse.Message);
Expand All @@ -551,10 +553,11 @@ async Task StreamEventHandler(IServerSentEvent streamEvent)
}

var run = await assistant.CreateThreadAndRunAsync("What date is it?", StreamEventHandler);
Assert.NotNull(thread);
Assert.IsNotNull(run);
Assert.IsTrue(hasInvokedCallback);
Assert.NotNull(thread);
Assert.IsFalse(exceptionThrown);
Assert.IsTrue(run.Status == RunStatus.Completed);
Assert.IsTrue(run.Status == RunStatus.Completed, $"Failed to complete run! {run.Status}");
}
finally
{
Expand All @@ -576,6 +579,7 @@ public async Task Test_04_04_CreateThreadAndRun_SubmitToolOutput()
Tool.CodeInterpreter,
Tool.GetOrCreateTool(typeof(WeatherService), nameof(WeatherService.GetCurrentWeatherAsync))
};
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null), "Expected all tool function arguments to be null");
var assistantRequest = new CreateAssistantRequest(tools: tools, instructions: "You are a helpful weather assistant. Use the appropriate unit based on geographical location.");
var assistant = await OpenAIClient.AssistantsEndpoint.CreateAssistantAsync(assistantRequest);
Assert.IsNotNull(assistant);
Expand Down Expand Up @@ -737,10 +741,11 @@ async Task StreamEventHandler(IServerSentEvent @event)
run = await run.WaitForStatusChangeAsync();
Assert.IsNotNull(run);
Assert.IsTrue(run.Status == RunStatus.Completed);
Console.WriteLine($"Created thread and run: {run.ThreadId} -> {run.Id} -> {run.CreatedAt}");
Assert.NotNull(thread);
var messages = await thread.ListMessagesAsync();

foreach (var response in messages.Items.OrderBy(response => response.CreatedAt))
foreach (var response in messages.Items)
{
Console.WriteLine($"{response.Role}: {response.PrintContent()}");
}
Expand Down
140 changes: 95 additions & 45 deletions OpenAI-DotNet-Tests/TestFixture_04_Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,9 @@ public async Task Test_01_01_GetChatCompletion()
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Assert.IsNotEmpty(response.Choices);

foreach (var choice in response.Choices)
{
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
}

Assert.AreEqual(1, response.Choices.Count);
Assert.IsNotNull(response.FirstChoice);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");
response.GetUsage();
}

Expand Down Expand Up @@ -78,7 +75,56 @@ public async Task Test_01_02_GetChatStreamingCompletion()
}

[Test]
public async Task Test_01_03_JsonMode()
public async Task Test_01_03_GetChatCompletion_Modalities()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);

var messages = new List<Message>
{
new(Role.System, "You are a helpful assistant."),
new(Role.User, "Is a golden retriever a good family dog?"),
};

var chatRequest = new ChatRequest(messages, Model.GPT4oAudio, audioConfig: Voice.Alloy);
Assert.IsNotNull(chatRequest);
Assert.IsNotNull(chatRequest.AudioConfig);
Assert.AreEqual(Model.GPT4oAudio.Id, chatRequest.Model);
Assert.AreEqual(Voice.Alloy.Id, chatRequest.AudioConfig.Voice);
Assert.AreEqual(AudioFormat.Pcm16, chatRequest.AudioConfig.Format);
Assert.AreEqual(Modality.Text | Modality.Audio, chatRequest.Modalities);
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Assert.IsNotEmpty(response.Choices);
Assert.AreEqual(1, response.Choices.Count);
Assert.IsNotNull(response.FirstChoice);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");
Assert.IsNotNull(response.FirstChoice.Message.AudioOutput.Data);
Assert.IsNotEmpty(response.FirstChoice.Message.AudioOutput.Data);
response.GetUsage();

messages.Add(response.FirstChoice.Message);
messages.Add(new(Role.User, "What are some other good family dog breeds?"));

chatRequest = new ChatRequest(messages, Model.GPT4oAudio, audioConfig: Voice.Alloy);
Assert.IsNotNull(chatRequest);
Assert.IsNotNull(messages[2]);
Assert.AreEqual(Role.Assistant, messages[2].Role);
Assert.IsNotNull(messages[2].AudioOutput);
response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Assert.IsNotEmpty(response.Choices);
Assert.AreEqual(1, response.Choices.Count);
Assert.IsNotNull(response.FirstChoice);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");
Assert.IsNotNull(response.FirstChoice.Message.AudioOutput.Data);
Assert.IsNotEmpty(response.FirstChoice.Message.AudioOutput.Data);
response.GetUsage();
}

[Test]
public async Task Test_01_04_JsonMode()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);
var messages = new List<Message>
Expand All @@ -101,7 +147,7 @@ public async Task Test_01_03_JsonMode()
}

[Test]
public async Task Test_01_04_GetChatStreamingCompletionEnumerableAsync()
public async Task Test_01_05_GetChatStreamingCompletionEnumerableAsync()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);
var messages = new List<Message>
Expand Down Expand Up @@ -149,6 +195,7 @@ public async Task Test_02_01_GetChatToolCompletion()
{
Tool.GetOrCreateTool(typeof(WeatherService), nameof(WeatherService.GetCurrentWeatherAsync))
};
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null));
var chatRequest = new ChatRequest(messages, tools: tools, toolChoice: "none");
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Expand Down Expand Up @@ -219,6 +266,7 @@ public async Task Test_02_02_GetChatToolCompletion_Streaming()
{
Tool.GetOrCreateTool(typeof(WeatherService), nameof(WeatherService.GetCurrentWeatherAsync))
};
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null));
var chatRequest = new ChatRequest(messages, tools: tools, toolChoice: "none");
var response = await OpenAIClient.ChatEndpoint.StreamCompletionAsync(chatRequest, partialResponse =>
{
Expand Down Expand Up @@ -302,14 +350,15 @@ public async Task Test_02_03_ChatCompletion_Multiple_Tools_Streaming()
};

var tools = Tool.GetAllAvailableTools(false, forceUpdate: true, clearCache: true);
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null));
var chatRequest = new ChatRequest(messages, model: Model.GPT4o, tools: tools, toolChoice: "auto", parallelToolCalls: true);
var response = await OpenAIClient.ChatEndpoint.StreamCompletionAsync(chatRequest, partialResponse =>
{
Assert.IsNotNull(partialResponse);
if (partialResponse.Usage != null) { return; }
Assert.NotNull(partialResponse.Choices);
Assert.NotZero(partialResponse.Choices.Count);
});
}, true);

Assert.IsTrue(response.FirstChoice.FinishReason == "tool_calls");
messages.Add(response.FirstChoice.Message);
Expand Down Expand Up @@ -347,6 +396,7 @@ public async Task Test_02_04_GetChatToolForceCompletion()
}

var tools = Tool.GetAllAvailableTools(false, forceUpdate: true, clearCache: true);
Assert.IsTrue(tools.All(tool => tool.Function?.Arguments == null));
var chatRequest = new ChatRequest(messages, tools: tools, toolChoice: "none");
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Expand Down Expand Up @@ -384,6 +434,39 @@ public async Task Test_02_04_GetChatToolForceCompletion()
Console.WriteLine($"{Role.Tool}: {functionResult}");
}

[Test]
public async Task Test_02_05_GetChat_Enumerable_TestToolCalls_Streaming()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);

var messages = new List<Message>
{
new(Role.System, "You must extract the name from the input"),
new(Role.User, "My name is Joe")
};

var tools = new List<Tool>
{
Tool.FromFunc("extract_first_name", (string name) => name)
};

var request = new ChatRequest(messages, tools);

await foreach (var streamResponse in OpenAIClient.ChatEndpoint.StreamCompletionEnumerableAsync(request))
{
Console.WriteLine(streamResponse.ToJsonString());

if (streamResponse.FirstChoice.Message is { } message)
{
foreach (var tool in message.ToolCalls)
{
var output = tool.InvokeFunction<string>();
Console.WriteLine($"Output from StreamCompletionEnumerableAsync: {output}");
}
}
}
}

[Test]
public async Task Test_03_01_GetChatVision()
{
Expand Down Expand Up @@ -425,7 +508,7 @@ public async Task Test_03_02_GetChatVisionStreaming()
if (partialResponse.Usage != null) { return; }
Assert.NotNull(partialResponse.Choices);
Assert.NotZero(partialResponse.Choices.Count);
});
}, true);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishDetails}");
Expand Down Expand Up @@ -496,40 +579,7 @@ public async Task Test_04_02_GetChatLogProbsStreaming()
}

[Test]
public async Task Test_05_02_GetChat_Enumerable_TestToolCalls_Streaming()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);

var messages = new List<Message>
{
new(Role.System, "You must extract the name from the input"),
new(Role.User, "My name is Joe")
};

var tools = new List<Tool>
{
Tool.FromFunc("extract_first_name", (string name) => name)
};

var request = new ChatRequest(messages, tools);

await foreach (var streamResponse in OpenAIClient.ChatEndpoint.StreamCompletionEnumerableAsync(request))
{
Console.WriteLine(streamResponse.ToJsonString());

if (streamResponse.FirstChoice.Message is { } message)
{
foreach (var tool in message.ToolCalls)
{
var output = tool.InvokeFunction<string>();
Console.WriteLine($"Output from StreamCompletionEnumerableAsync: {output}");
}
}
}
}

[Test]
public async Task Test_06_01_GetChat_JsonSchema()
public async Task Test_05_01_GetChat_JsonSchema()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);

Expand Down Expand Up @@ -562,7 +612,7 @@ public async Task Test_06_01_GetChat_JsonSchema()
}

[Test]
public async Task Test_06_01_GetChat_JsonSchema_Streaming()
public async Task Test_05_02_GetChat_JsonSchema_Streaming()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);

Expand Down

0 comments on commit 9354fdd

Please sign in to comment.