Skip to content

Commit

Permalink
[C#] bump: dotnet 1.8.0 (#2159)
Browse files Browse the repository at this point in the history
## Linked issues

closes: #minor

## Details
Changes since 1.7.0
* o1 model support
* Streaming error suppression bug fix
* Azure AI Content Safety api version update
* UI/UX features: AI Label, Feedback Loop, Citations, Sensitivity
Label...etc
* Streaming

## Attestation Checklist

- [x] My code follows the style guidelines of this project

- I have checked for/fixed spelling, linting, and other errors
- I have commented my code for clarity
- I have made corresponding changes to the documentation (updating the
doc strings in the code is sufficient)
- My changes generate no new warnings
- I have added tests that validates my changes, and provides sufficient
test coverage. I have tested with:
  - Local testing
  - E2E testing in Teams
- New and existing unit tests pass locally with my changes

---------

Co-authored-by: Lily Du <[email protected]>
Co-authored-by: lilydu <[email protected]>
  • Loading branch information
3 people authored Oct 31, 2024
1 parent 3509d08 commit ec81697
Show file tree
Hide file tree
Showing 84 changed files with 1,780 additions and 327 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public async Task Test_ContinueTaskAsync_Streaming()
await state.LoadStateAsync(null, turnContext);
state.Temp.Input = "test";
var planner = new ActionPlanner<TurnState>(options, new TestLoggerFactory());
var ai = new AI<TurnState>(new(planner));
var ai = new AI<TurnState>(new(planner) { EnableFeedbackLoop = true });

// Act
var result = await planner.ContinueTaskAsync(turnContext, state, ai);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void Test_Constructor()
{
// Arrange
MessageContent content = OpenAIModelFactory.CreateMessageContent("message", "fileId");
Mock<FileClient> fileClientMock = new Mock<FileClient>();
Mock<OpenAIFileClient> fileClientMock = new Mock<OpenAIFileClient>();
fileClientMock.Setup(fileClient => fileClient.DownloadFileAsync("fileId", It.IsAny<CancellationToken>())).Returns(() =>
{
return Task.FromResult(ClientResult.FromValue(BinaryData.FromString("test"), new Mock<PipelineResponse>().Object));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public async Task Test_ReviewPrompt_Flagged(ModerationType moderate)
};

var clientMock = new Mock<ContentSafetyClient>(new Uri(endpoint), new AzureKeyCredential(apiKey));
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(hateResult: ContentSafetyModelFactory.TextAnalyzeSeverityResult(TextCategory.Hate, 2));
var analyses = new List<TextCategoriesAnalysis>() { ContentSafetyModelFactory.TextCategoriesAnalysis(TextCategory.Hate, 2) };
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(null, analyses);
Response? response = null;
clientMock.Setup(client => client.AnalyzeTextAsync(It.IsAny<AnalyzeTextOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(Response.FromValue(analyzeTextResult, response));

Expand Down Expand Up @@ -173,7 +174,8 @@ public async Task Test_ReviewPrompt_NotFlagged(ModerationType moderate)
};

var clientMock = new Mock<ContentSafetyClient>(new Uri(endpoint), new AzureKeyCredential(apiKey));
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(hateResult: ContentSafetyModelFactory.TextAnalyzeSeverityResult(TextCategory.Hate, 0));
var analyses = new List<TextCategoriesAnalysis>() { ContentSafetyModelFactory.TextCategoriesAnalysis(TextCategory.Hate, 0) };
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(null, analyses);
Response? response = null;
clientMock.Setup(client => client.AnalyzeTextAsync(It.IsAny<AnalyzeTextOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(Response.FromValue(analyzeTextResult, response));

Expand Down Expand Up @@ -237,7 +239,8 @@ public async Task Test_ReviewPlan_Flagged(ModerationType moderate)
});

var clientMock = new Mock<ContentSafetyClient>(new Uri(endpoint), new AzureKeyCredential(apiKey));
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(hateResult: ContentSafetyModelFactory.TextAnalyzeSeverityResult(TextCategory.Hate, 2));
var analyses = new List<TextCategoriesAnalysis>() { ContentSafetyModelFactory.TextCategoriesAnalysis(TextCategory.Hate, 2) };
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(null, analyses);
Response? response = null;
clientMock.Setup(client => client.AnalyzeTextAsync(It.IsAny<AnalyzeTextOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(Response.FromValue(analyzeTextResult, response));

Expand Down Expand Up @@ -298,7 +301,8 @@ public async Task Test_ReviewPlan_NotFlagged(ModerationType moderate)
});

var clientMock = new Mock<ContentSafetyClient>(new Uri(endpoint), new AzureKeyCredential(apiKey));
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(hateResult: ContentSafetyModelFactory.TextAnalyzeSeverityResult(TextCategory.Hate, 0));
var analyses = new List<TextCategoriesAnalysis>() { ContentSafetyModelFactory.TextCategoriesAnalysis(TextCategory.Hate, 0) };
AnalyzeTextResult analyzeTextResult = ContentSafetyModelFactory.AnalyzeTextResult(null, analyses);
Response? response = null;
clientMock.Setup(client => client.AnalyzeTextAsync(It.IsAny<AnalyzeTextOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(Response.FromValue(analyzeTextResult, response));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void Test_Initialization_From_OpenAISdk_ChatMessage()
""citations"": [
{{
""title"": ""test-title"",
""url"": ""test-url"",
""url"": ""https://www.test-uri.com/"",
""content"": ""test-content""
}}
]
Expand All @@ -69,7 +69,7 @@ public void Test_Initialization_From_OpenAISdk_ChatMessage()
Assert.NotNull(context);
Assert.Single(context.Citations);
Assert.Equal("test-title", context.Citations[0].Title);
Assert.Equal("test-url", context.Citations[0].Url);
Assert.Equal("https://www.test-uri.com/", context.Citations[0].Url);
Assert.Equal("test-content", context.Citations[0].Content);
}

Expand Down Expand Up @@ -179,10 +179,10 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_FunctionCall()
// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
Assert.Empty(assistantMessage.Content);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("test-name", assistantMessage.ParticipantName);
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments);
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments.ToString());
Assert.Equal("test-name", assistantMessage.FunctionCall.FunctionName);
}

Expand All @@ -206,7 +206,7 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_ActionCall()
// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
Assert.Empty(assistantMessage.Content);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("test-name", assistantMessage.ParticipantName);

Expand All @@ -215,7 +215,7 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_ActionCall()
Assert.NotNull(toolCall);
Assert.Equal("test-id", toolCall.Id);
Assert.Equal("test-tool-name", toolCall.FunctionName);
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments);
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments.ToString());
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public async Task Test_CompletePromptAsync_Streaming_Success()
{
StartStreamingMessage = "Begin streaming",
EndStreamHandler = handler,
EnableFeedbackLoop = true,
};
LLMClient<object> client = new(options, null);
TestMemory memory = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public sealed class ChatCompletionToolCallTests
public void Test_ChatCompletionsToolCall_ToFunctionToolCall()
{
// Arrange
var functionToolCall = ChatToolCall.CreateFunctionToolCall("test-id", "test-name", "test-arg1");
var functionToolCall = ChatToolCall.CreateFunctionToolCall("test-id", "test-name", BinaryData.FromString("test-arg1"));

// Act
var azureSdkFunctionToolCall = ChatCompletionsToolCall.FromChatToolCall(functionToolCall);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_FunctionCall()
// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
Assert.Empty(assistantMessage.Content);
// TODO: Uncomment when participant name issue is resolved.
//Assert.Equal("test-name", assistantMessage.ParticipantName);
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments);
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments.ToString());
Assert.Equal("test-name", assistantMessage.FunctionCall.FunctionName);
}

Expand All @@ -113,14 +113,14 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_ToolCall()
// Assert
var assistantMessage = result as AssistantChatMessage;
Assert.NotNull(assistantMessage);
Assert.Equal("test-content", assistantMessage.Content[0].Text);
Assert.Empty(assistantMessage.Content);

Assert.Single(assistantMessage.ToolCalls);
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);
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments.ToString());
}

[Fact]
Expand Down Expand Up @@ -198,7 +198,7 @@ public void Test_ChatCompletionsToolCall_ToFunctionToolCall()
Assert.NotNull(chatToolCall);
Assert.Equal("test-id", chatToolCall.Id);
Assert.Equal("test-name", chatToolCall.FunctionName);
Assert.Equal("test-arg1", chatToolCall.FunctionArguments);
Assert.Equal("test-arg1", chatToolCall.FunctionArguments.ToString());
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,33 @@ public void Test_Constructor_OpenAI()
new OpenAIModel(options);
}

[Fact]
public void Test_SetMaxTokens()
{
// Arrange
var options = new OpenAIModelOptions("test-key", "test-model");
var chatCompletionOptions = new ChatCompletionOptions();
var model = new OpenAIModel(options);
var testTokens = 100;

// Act
model.SetMaxTokens(testTokens, chatCompletionOptions);

// Assert
MethodInfo info = chatCompletionOptions.GetType().GetMethod("get__deprecatedMaxTokens", BindingFlags.NonPublic | BindingFlags.Instance)!;
int maxTokens = (int)info.Invoke(chatCompletionOptions, null)!;
Assert.Equal(testTokens, maxTokens);
}


[Fact]
public void Test_Constructor_AzureOpenAI_InvalidAzureApiVersion()
{
// Arrange
var options = new AzureOpenAIModelOptions("test-key", "test-deployment", "https://test.openai.azure.com/");
var versions = new List<string>
{
"2024-04-01-preview", "2024-05-01-preview", "2024-06-01"
"2024-06-01", "2024-08-01-preview", "2024-10-01-preview"
};

// Act
Expand Down Expand Up @@ -279,8 +298,8 @@ public async Task Test_CompletePromptAsync_AzureOpenAI_Chat_WithTools()

Assert.NotNull(result.Message.ActionCalls);
Assert.Single(result.Message.ActionCalls);
Assert.Equal("testAction", result.Message.ActionCalls[0].Function.Name);

Assert.Equal("testAction", result.Message.ActionCalls[0].Function!.Name);
Assert.Null(result.Error);
Assert.Equal(ChatRole.Assistant, result.Message.Role);
Assert.Null(result.Message.Content);
Expand Down Expand Up @@ -326,7 +345,7 @@ public async Task Test_CompletePromptAsync_AzureOpenAI_Streaming()
]
}}"));

TestAsyncResultCollection<StreamingChatCompletionUpdate> updates = new(update!, Mock.Of<PipelineResponse>());
TestAsyncCollectionResult<StreamingChatCompletionUpdate> updates = new(update!, Mock.Of<PipelineResponse>());

var response = new TestResponse(200, string.Empty);
clientMock.Setup((client) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public async Task Test_OpenAI_CreateEmbeddings_ReturnEmbeddings()
IList<string> inputs = new List<string> { "test" };
var clientMock = new Mock<OpenAIClient>(new ApiKeyCredential(apiKey), It.IsAny<OpenAIClientOptions>());
var response = new TestResponse(200, string.Empty);
var embeddingCollection = ModelReaderWriter.Read<EmbeddingCollection>(BinaryData.FromString(@"{
var embeddingCollection = ModelReaderWriter.Read<OpenAIEmbeddingCollection>(BinaryData.FromString(@"{
""data"": [
{
""object"": ""embedding"",
Expand Down Expand Up @@ -76,7 +76,7 @@ public async Task Test_AzureOpenAI_CreateEmbeddings_ReturnEmbeddings()
IList<string> inputs = new List<string> { "test" };
var clientMock = new Mock<OpenAIClient>(new ApiKeyCredential(apiKey), It.IsAny<OpenAIClientOptions>());
var response = new TestResponse(200, string.Empty);
var embeddingCollection = ModelReaderWriter.Read<EmbeddingCollection>(BinaryData.FromString(@"{
var embeddingCollection = ModelReaderWriter.Read<OpenAIEmbeddingCollection>(BinaryData.FromString(@"{
""data"": [
{
""object"": ""embedding"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
using AdaptiveCards;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Teams.AI.AI.Action;
using Microsoft.Teams.AI.AI.Models;
using Microsoft.Teams.AI.Application;
using Microsoft.Teams.AI.Exceptions;
using Microsoft.Teams.AI.Tests.TestUtils;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using Moq;

namespace Microsoft.Teams.AI.Tests.Application
{
Expand Down Expand Up @@ -196,6 +200,37 @@ void CaptureSend(Activity[] arg)
Assert.Equal(2, streamer.UpdatesSent());
}

[Fact]
public async Task Test_SendTextChunk_SendsFinalMessageWithPoweredByAIFeatures()
{
// Arrange
Activity[]? activitiesToSend = null;
void CaptureSend(Activity[] arg)
{
activitiesToSend = arg;
}
var adapter = new SimpleAdapter(CaptureSend);
ITurnContext turnContext = new TurnContext(adapter, new Activity(
text: "hello",
channelId: "channelId",
recipient: new() { Id = "recipientId" },
conversation: new() { Id = "conversationId" },
from: new() { Id = "fromId" }
));
StreamingResponse streamer = new(turnContext);
List<Citation> citations = new List<Citation>();
citations.Add(new Citation(content: "test-content", title: "test", url: "https://example.com"));
streamer.QueueTextChunk("first", citations);
await streamer.WaitForQueue();
streamer.QueueTextChunk("second");
await streamer.WaitForQueue();
streamer.EnableFeedbackLoop = true;
streamer.EnableGeneratedByAILabel = true;
streamer.SensitivityLabel = new SensitivityUsageInfo() { Name= "Sensitivity"};
await streamer.EndStream();
Assert.Equal(2, streamer.UpdatesSent());
}

[Fact]
public async Task Test_SendTextChunk_SendsFinalMessageWithAttachments()
{
Expand Down Expand Up @@ -233,6 +268,32 @@ void CaptureSend(Activity[] arg)
await streamer.EndStream();
Assert.Equal(2, streamer.UpdatesSent());
Assert.Single(streamer.Attachments);
if (streamer.Citations != null)
{
Assert.Empty(streamer.Citations);
}
}

[Fact]
public async Task Test_SendActivityThrowsException_AssertThrows()
{
// Arrange
Activity[]? activitiesToSend = null;
void CaptureSend(Activity[] arg)
{
activitiesToSend = arg;
}
var adapter = new SimpleAdapter(CaptureSend);
var turnContextMock = new Mock<ITurnContext>();
turnContextMock.Setup((tc) => tc.SendActivityAsync(It.IsAny<Activity>(), It.IsAny<CancellationToken>())).ThrowsAsync(new Exception("Forbidden operation"));

// Act
StreamingResponse streamer = new(turnContextMock.Object);
Exception ex = await Assert.ThrowsAsync<TeamsAIException>(() => streamer.EndStream());


// Assert
Assert.Equal("Error occurred when sending activity while streaming", ex.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.0.0-beta.5" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0-beta.1" />
<PackageReference Include="Azure.Identity" Version="1.12.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.Bot.Builder" Version="4.22.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="OpenAI" Version="2.0.0-beta.11" />
<PackageReference Include="OpenAI" Version="2.1.0-beta.1" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
Expand Down
Loading

0 comments on commit ec81697

Please sign in to comment.