Skip to content
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

[C#] bump: Migrate to OpenAI's official .NET SDK #1858

Merged
merged 9 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
@@ -1,4 +1,8 @@
using Microsoft.Teams.AI.AI.Models;
using Microsoft.Teams.AI.Exceptions;
using OpenAI.Chat;
using System.ClientModel.Primitives;
using ChatMessage = Microsoft.Teams.AI.AI.Models.ChatMessage;

namespace Microsoft.Teams.AI.Tests.AITests
{
Expand Down Expand Up @@ -28,5 +32,224 @@
// Act & Assert
Assert.Throws<InvalidCastException>(() => msg.GetContent<bool>());
}

[Fact]
public void Test_Initialization_From_OpenAISdk_ChatMessage()
{
// Arrange
var chatCompletion = ModelReaderWriter.Read<ChatCompletion>(BinaryData.FromString(@$"{{
""choices"": [
{{
""finish_reason"": ""stop"",
""message"": {{
""role"": ""assistant"",
""content"": ""test-choice"",
""context"": {{
""citations"": [
{{
""title"": ""test-title"",
""url"": ""test-url"",
""content"": ""test-content""
}}
]
}}
}}
}}
]
}}"));

// Act
var message = new ChatMessage(chatCompletion!);

// Assert
Assert.Equal("test-choice", message.Content);
Assert.Equal(ChatRole.Assistant, message.Role);

var context = message.Context;
Assert.NotNull(context);
Assert.Equal(1, context.Citations.Count);
Assert.Equal("test-title", context.Citations[0].Title);
Assert.Equal("test-url", context.Citations[0].Url);
Assert.Equal("test-content", context.Citations[0].Content);
}

[Fact]
public void Test_InvalidRole_ToOpenAISdkChatMessage()
{
// Arrange
var chatMessage = new ChatMessage(new ChatRole("InvalidRole"))
{
Content = "test"
};

// Act
var ex = Assert.Throws<TeamsAIException>(() => chatMessage.ToOpenAIChatMessage());

// Assert
Assert.Equal($"Invalid chat message role: InvalidRole", ex.Message);
}

[Fact]
public void Test_UserRole_StringContent_ToOpenAISdkChatMessage()
{
// Arrange
var chatMessage = new ChatMessage(ChatRole.User)
{
Content = "test-content",
Name = "author"
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var userMessage = result as UserChatMessage;
Assert.NotNull(userMessage);
Assert.Equal("test-content", result.Content[0].Text);
// TODO: Uncomment once participant name issue is resolved.
//Assert.Equal("author", userMessage.ParticipantName);
}

[Fact]
public void Test_UserRole_MultiModalContent_ToOpenAISdkChatMessage()
{
// Arrange
var messageContentParts = new List<MessageContentParts>() { new TextContentPart() { Text = "test" }, new ImageContentPart { ImageUrl = "https://www.testurl.com" } };
var chatMessage = new ChatMessage(ChatRole.User)
{
Content = messageContentParts,
Name = "author"
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var userMessage = result as UserChatMessage;
Assert.NotNull(userMessage);
Assert.Equal("test", userMessage.Content[0].Text);
Assert.Equal("https://www.testurl.com", userMessage.Content[1].ImageUri.OriginalString);

// TODO: Uncomment once participant name issue is resolved.
//Assert.Equal("author", userMessage.ParticipantName);
}

[Fact]
public void Test_AssistantRole_ToOpenAISdkChatMessage_FunctionCall()
{
// Arrange
var functionCall = new FunctionCall("test-name", "test-arg1");
var chatMessage = new ChatMessage(ChatRole.Assistant)
{
Content = "test-content",
Name = "test-name",
FunctionCall = functionCall,
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("test-name", assistantMessage.ParticipantName);
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments);
Assert.Equal("test-name", assistantMessage.FunctionCall.FunctionName);
}

[Fact]
public void Test_AssistantRole_ToOpenAISdkChatMessage_ToolCall()
{
// Arrange
var chatMessage = new ChatMessage(ChatRole.Assistant)
{
Content = "test-content",
Name = "test-name",
ToolCalls = new List<ChatCompletionsToolCall>()
{
new ChatCompletionsFunctionToolCall("test-id", "test-tool-name", "test-tool-arg1")
}
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("test-name", assistantMessage.ParticipantName);

Assert.Equal(1, assistantMessage.ToolCalls.Count);
ChatToolCall toolCall = assistantMessage.ToolCalls[0];
Assert.NotNull(toolCall);
Assert.Equal("test-id", toolCall.Id);
Assert.Equal("test-tool-name", toolCall.FunctionName);
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments);
}

[Fact]
public void Test_SystemRole_ToOpenAISdkChatMessage()
{
// Arrange
var chatMessage = new ChatMessage(ChatRole.System)
{
Content = "test-content",
Name = "author"
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var systemMessage = result as SystemChatMessage;
Assert.NotNull(systemMessage);
Assert.Equal("test-content", systemMessage.Content[0].Text);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("author", systemMessage.ParticipantName);
}

[Fact]
public void Test_FunctionRole_ToOpenAISdkChatMessage()
{
// Arrange
var chatMessage = new ChatMessage(ChatRole.Function)
{
Content = "test-content",
Name = "function-name"
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var functionMessage = result as FunctionChatMessage;

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (6.0)

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (6.0)

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (7.0)

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (7.0)

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Analyze

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'

Check warning on line 229 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

View workflow job for this annotation

GitHub Actions / Analyze

'FunctionChatMessage' is obsolete: 'This field is marked as deprecated.'
Assert.NotNull(functionMessage);
Assert.Equal("test-content", functionMessage.Content[0].Text);
}

[Fact]
public void Test_ToolRole_ToOpenAISdkChatMessage()
{
// Arrange
var chatMessage = new ChatMessage(ChatRole.Tool)
{
Content = "test-content",
Name = "tool-name",
ToolCallId = "tool-call-id"
};

// Act
var result = chatMessage.ToOpenAIChatMessage();

// Assert
var toolMessage = result as ToolChatMessage;
Assert.NotNull(toolMessage);
Assert.Equal("test-content", toolMessage.Content[0].Text);
Assert.Equal("tool-call-id", toolMessage.ToolCallId);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
using Microsoft.Teams.AI.AI.Models;
using Microsoft.Teams.AI.Exceptions;
using OpenAI.Chat;

namespace Microsoft.Teams.AI.Tests.AITests.Models
{
public class AzureSdkChatMessageExtensions
internal class ChatCompletionToolCallTests

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (6.0)

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (6.0)

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (7.0)

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Build/Test/Lint (7.0)

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Analyze

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)

Check warning on line 7 in dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

View workflow job for this annotation

GitHub Actions / Analyze

Type 'ChatCompletionToolCallTests' can be sealed because it has no subtypes in its containing assembly and is not externally visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)
{
[Fact]
public void Test_ChatCompletionsToolCall_ToFunctionToolCall()
{
// Arrange
var functionToolCall = new Azure.AI.OpenAI.ChatCompletionsFunctionToolCall("test-id", "test-name", "test-arg1");
var functionToolCall = ChatToolCall.CreateFunctionToolCall("test-id", "test-name", "test-arg1");

// Act
var azureSdkFunctionToolCall = functionToolCall.ToChatCompletionsToolCall();
var azureSdkFunctionToolCall = ChatCompletionsToolCall.FromChatToolCall(functionToolCall);

// Assert
var toolCall = azureSdkFunctionToolCall as ChatCompletionsFunctionToolCall;
Expand All @@ -29,15 +30,15 @@
var functionToolCall = new InvalidToolCall();

// Act
var ex = Assert.Throws<TeamsAIException>(() => functionToolCall.ToChatCompletionsToolCall());
var ex = Assert.Throws<TeamsAIException>(() => functionToolCall.ToChatToolCall());

// Assert
Assert.Equal($"Invalid ChatCompletionsToolCall type: {nameof(InvalidToolCall)}", ex.Message);
Assert.Equal("Invalid tool type: invalidToolType", ex.Message);
}

private sealed class InvalidToolCall : Azure.AI.OpenAI.ChatCompletionsToolCall
private sealed class InvalidToolCall : ChatCompletionsToolCall
{
public InvalidToolCall() : base("test-id")
public InvalidToolCall() : base("invalidToolType", "test-id")
{
}
}
Expand Down
Loading
Loading