Skip to content

.Net: Cross-language tests #6196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ internal async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsy
// Make the request.
var responseData = (await RunRequestAsync(() => this.Client.GetChatCompletionsAsync(chatOptions, cancellationToken)).ConfigureAwait(false)).Value;
this.CaptureUsageDetails(responseData.Usage);
if (responseData.Choices.Count == 0)
if (responseData.Choices is null || responseData.Choices.Count == 0)
{
throw new KernelException("Chat completions not found");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"messages": [
{
"content": "Can you help me tell the time in Seattle right now?",
"role": "user"
},
{
"content": "Sure! The time in Seattle is currently 3:00 PM.",
"role": "assistant"
},
{
"content": "What about New York?",
"role": "user"
}
],
"temperature": 1,
"top_p": 1,
"n": 1,
"presence_penalty": 0,
"frequency_penalty": 0,
"model": "Dummy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"messages": [
{
"content": "The current time is Sun, 04 Jun 1989 12:11:13 GMT",
"role": "system"
},
{
"content": "Can you help me tell the time in Seattle right now?",
"role": "user"
}
],
"temperature": 1,
"top_p": 1,
"n": 1,
"presence_penalty": 0,
"frequency_penalty": 0,
"model": "Dummy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"messages": [
{
"content": "Can you help me tell the time in Seattle right now?",
"role": "user"
}
],
"temperature": 1,
"top_p": 1,
"n": 1,
"presence_penalty": 0,
"frequency_penalty": 0,
"model": "Dummy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"messages": [
{
"content": "Can you help me tell the time in Seattle right now?",
"role": "user"
}
],
"temperature": 1,
"top_p": 1,
"n": 1,
"presence_penalty": 0,
"frequency_penalty": 0,
"model": "Dummy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using SemanticKernel.UnitTests;

namespace SemanticKernel.IntegrationTests.CrossLanguage;

internal sealed class KernelRequestTracer : IDisposable
{
private const string DummyResponse = @"{
""id"": ""chatcmpl-abc123"",
""object"": ""chat.completion"",
""created"": 1677858242,
""model"": ""gpt-3.5-turbo-0613"",
""usage"": {
""prompt_tokens"": 13,
""completion_tokens"": 7,
""total_tokens"": 20
},
""choices"": [
{
""message"": {
""role"": ""assistant"",
""content"": ""\n\nThis is a test!""
},
""logprobs"": null,
""finish_reason"": ""stop"",
""index"": 0
}
]
}";

private HttpClient? _httpClient;
private HttpMessageHandlerStub? _httpMessageHandlerStub;

public Kernel GetNewKernel()
{
this.ResetHttpComponents();

return Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
modelId: "Dummy",
apiKey: "Not used in this test",
httpClient: this._httpClient)
.Build();
}

public string GetRequestContent()
{
return System.Text.Encoding.UTF8.GetString(this._httpMessageHandlerStub?.RequestContent ?? Array.Empty<byte>());
}

public static async Task InvokePromptStreamingAsync(Kernel kernel, string prompt, KernelArguments? args = null)
{
try
{
await foreach (var update in kernel.InvokePromptStreamingAsync<ChatMessageContent>(prompt, arguments: args))
{
// Do nothing with received response
}
}
catch (NotSupportedException)
{
// Ignore this exception
}
}

private void ResetHttpComponents()
{
this.DisposeHttpResources();

this._httpMessageHandlerStub = new HttpMessageHandlerStub();
this._httpMessageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(DummyResponse,
Encoding.UTF8, "application/json")
};
this._httpClient = new HttpClient(this._httpMessageHandlerStub);
}

public void Dispose()
{
this.DisposeHttpResources();
GC.SuppressFinalize(this);
}

private void DisposeHttpResources()
{
this._httpClient?.Dispose();
this._httpMessageHandlerStub?.Dispose();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.

using System.IO;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Xunit;

namespace SemanticKernel.IntegrationTests.CrossLanguage;

public class PromptWithChatRolesTest
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task PromptWithChatRolesAsync(bool isStreaming)
{
const string Prompt = "<message role=\"user\">Can you help me tell the time in Seattle right now?</message><message role=\"assistant\">Sure! The time in Seattle is currently 3:00 PM.</message><message role=\"user\">What about New York?</message>";

using var kernelProvider = new KernelRequestTracer();

Kernel kernel = kernelProvider.GetNewKernel();
if (isStreaming)
{
await KernelRequestTracer.InvokePromptStreamingAsync(kernel, Prompt);
}
else
{
await kernel.InvokePromptAsync<ChatMessageContent>(Prompt);
}
string requestContent = kernelProvider.GetRequestContent();
JsonNode? obtainedObject = JsonNode.Parse(requestContent);
Assert.NotNull(obtainedObject);

string expected = await File.ReadAllTextAsync("./CrossLanguage/Data/PromptWithChatRolesTest.json");
JsonNode? expectedObject = JsonNode.Parse(expected);
Assert.NotNull(expectedObject);

if (isStreaming)
{
expectedObject["stream"] = true;
}

Assert.True(JsonNode.DeepEquals(obtainedObject, expectedObject));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.SemanticKernel;
using System;
using System.IO;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Xunit;

namespace SemanticKernel.IntegrationTests.CrossLanguage;

public class PromptWithHelperFunctions
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task PromptWithHelperFunctionsAsync(bool isStreaming)
{
const string Prompt = "<message role=\"system\">The current time is {{Time.Now}}</message><message role=\"user\">Can you help me tell the time in {{$city}} right now?</message>";

using var kernelProvider = new KernelRequestTracer();

Kernel kernel = kernelProvider.GetNewKernel();
kernel.Plugins.AddFromFunctions("Time",
[KernelFunctionFactory.CreateFromMethod(() => $"{PromptWithHelperFunctions.UtcNow:r}", "Now", "Gets the current date and time")]);
if (isStreaming)
{
await KernelRequestTracer.InvokePromptStreamingAsync(kernel, Prompt, new()
{
{ "city", "Seattle" }
});
}
else
{
await kernel.InvokePromptAsync<ChatMessageContent>(Prompt, arguments: new()
{
{ "city", "Seattle" }
});
}
string requestContent = kernelProvider.GetRequestContent();
JsonNode? obtainedObject = JsonNode.Parse(requestContent);
Assert.NotNull(obtainedObject);

string expected = await File.ReadAllTextAsync("./CrossLanguage/Data/PromptWithHelperFunctionsTest.json");
JsonNode? expectedObject = JsonNode.Parse(expected);
Assert.NotNull(expectedObject);

if (isStreaming)
{
expectedObject["stream"] = true;
}

Assert.True(JsonNode.DeepEquals(obtainedObject, expectedObject));
}

/// <summary>
/// Returns a constant timestamp for test purposes.
/// </summary>
internal static DateTime UtcNow => new(1989, 6, 4, 12, 11, 13);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.

using System.IO;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Xunit;

namespace SemanticKernel.IntegrationTests.CrossLanguage;

public class PromptWithSimpleVariableTest
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task PromptWithSimpleVariableAsync(bool isStreaming)
{
const string Prompt = "Can you help me tell the time in {{$city}} right now?";

using var kernelProvider = new KernelRequestTracer();

Kernel kernel = kernelProvider.GetNewKernel();
if (isStreaming)
{
await KernelRequestTracer.InvokePromptStreamingAsync(kernel, Prompt, new()
{
{ "city", "Seattle" }
});
}
else
{
await kernel.InvokePromptAsync<ChatMessageContent>(Prompt, arguments: new()
{
{ "city", "Seattle" }
});
}
string requestContent = kernelProvider.GetRequestContent();
JsonNode? obtainedObject = JsonNode.Parse(requestContent);
Assert.NotNull(obtainedObject);

string expected = await File.ReadAllTextAsync("./CrossLanguage/Data/PromptWithSimpleVariableTest.json");
JsonNode? expectedObject = JsonNode.Parse(expected);
Assert.NotNull(expectedObject);

if (isStreaming)
{
expectedObject["stream"] = true;
}

Assert.True(JsonNode.DeepEquals(obtainedObject, expectedObject));
}
}
46 changes: 46 additions & 0 deletions dotnet/src/IntegrationTests/CrossLanguage/SimplePromptTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.

using System.IO;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Xunit;

namespace SemanticKernel.IntegrationTests.CrossLanguage;

public class SimplePromptTest
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task SimplePromptAsync(bool isStreaming)
{
const string Prompt = "Can you help me tell the time in Seattle right now?";

using var kernelProvider = new KernelRequestTracer();

Kernel kernel = kernelProvider.GetNewKernel();
if (isStreaming)
{
await KernelRequestTracer.InvokePromptStreamingAsync(kernel, Prompt);
}
else
{
await kernel.InvokePromptAsync<ChatMessageContent>(Prompt);
}
string requestContent = kernelProvider.GetRequestContent();
JsonNode? obtainedObject = JsonNode.Parse(requestContent);
Assert.NotNull(obtainedObject);

string expected = await File.ReadAllTextAsync("./CrossLanguage/Data/SimplePromptTest.json");
JsonNode? expectedObject = JsonNode.Parse(expected);
Assert.NotNull(expectedObject);

if (isStreaming)
{
expectedObject["stream"] = true;
}

Assert.True(JsonNode.DeepEquals(obtainedObject, expectedObject));
}
}
Loading
Loading