Skip to content

Commit ec81697

Browse files
singhk97lilyydulilydu
authored
[C#] bump: dotnet 1.8.0 (#2159)
## 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]>
1 parent 3509d08 commit ec81697

File tree

84 files changed

+1780
-327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1780
-327
lines changed

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ActionPlannerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ public async Task Test_ContinueTaskAsync_Streaming()
328328
await state.LoadStateAsync(null, turnContext);
329329
state.Temp.Input = "test";
330330
var planner = new ActionPlanner<TurnState>(options, new TestLoggerFactory());
331-
var ai = new AI<TurnState>(new(planner));
331+
var ai = new AI<TurnState>(new(planner) { EnableFeedbackLoop = true });
332332

333333
// Act
334334
var result = await planner.ContinueTaskAsync(turnContext, state, ai);

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/AssistantMessageTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public void Test_Constructor()
1515
{
1616
// Arrange
1717
MessageContent content = OpenAIModelFactory.CreateMessageContent("message", "fileId");
18-
Mock<FileClient> fileClientMock = new Mock<FileClient>();
18+
Mock<OpenAIFileClient> fileClientMock = new Mock<OpenAIFileClient>();
1919
fileClientMock.Setup(fileClient => fileClient.DownloadFileAsync("fileId", It.IsAny<CancellationToken>())).Returns(() =>
2020
{
2121
return Task.FromResult(ClientResult.FromValue(BinaryData.FromString("test"), new Mock<PipelineResponse>().Object));

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/AzureContentSafetyModeratorTests.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ public async Task Test_ReviewPrompt_Flagged(ModerationType moderate)
9797
};
9898

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

@@ -173,7 +174,8 @@ public async Task Test_ReviewPrompt_NotFlagged(ModerationType moderate)
173174
};
174175

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

@@ -237,7 +239,8 @@ public async Task Test_ReviewPlan_Flagged(ModerationType moderate)
237239
});
238240

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

@@ -298,7 +301,8 @@ public async Task Test_ReviewPlan_NotFlagged(ModerationType moderate)
298301
});
299302

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

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/ChatMessageTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void Test_Initialization_From_OpenAISdk_ChatMessage()
4848
""citations"": [
4949
{{
5050
""title"": ""test-title"",
51-
""url"": ""test-url"",
51+
""url"": ""https://www.test-uri.com/"",
5252
""content"": ""test-content""
5353
}}
5454
]
@@ -69,7 +69,7 @@ public void Test_Initialization_From_OpenAISdk_ChatMessage()
6969
Assert.NotNull(context);
7070
Assert.Single(context.Citations);
7171
Assert.Equal("test-title", context.Citations[0].Title);
72-
Assert.Equal("test-url", context.Citations[0].Url);
72+
Assert.Equal("https://www.test-uri.com/", context.Citations[0].Url);
7373
Assert.Equal("test-content", context.Citations[0].Content);
7474
}
7575

@@ -179,10 +179,10 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_FunctionCall()
179179
// Assert
180180
var assistantMessage = result as AssistantChatMessage;
181181
Assert.NotNull(assistantMessage);
182-
Assert.Equal("test-content", assistantMessage.Content[0].Text);
182+
Assert.Empty(assistantMessage.Content);
183183
// TODO: Uncomment when participant name issue is resolved.
184184
//Assert.Equal("test-name", assistantMessage.ParticipantName);
185-
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments);
185+
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments.ToString());
186186
Assert.Equal("test-name", assistantMessage.FunctionCall.FunctionName);
187187
}
188188

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

@@ -215,7 +215,7 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_ActionCall()
215215
Assert.NotNull(toolCall);
216216
Assert.Equal("test-id", toolCall.Id);
217217
Assert.Equal("test-tool-name", toolCall.FunctionName);
218-
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments);
218+
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments.ToString());
219219
}
220220

221221
[Fact]

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/LLMClientTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ public async Task Test_CompletePromptAsync_Streaming_Success()
176176
{
177177
StartStreamingMessage = "Begin streaming",
178178
EndStreamHandler = handler,
179+
EnableFeedbackLoop = true,
179180
};
180181
LLMClient<object> client = new(options, null);
181182
TestMemory memory = new();

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatCompletionToolCallTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public sealed class ChatCompletionToolCallTests
1111
public void Test_ChatCompletionsToolCall_ToFunctionToolCall()
1212
{
1313
// Arrange
14-
var functionToolCall = ChatToolCall.CreateFunctionToolCall("test-id", "test-name", "test-arg1");
14+
var functionToolCall = ChatToolCall.CreateFunctionToolCall("test-id", "test-name", BinaryData.FromString("test-arg1"));
1515

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

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/ChatMessageExtensionsTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ public void Test_AssistantRole_ToOpenAISdkChatMessage_FunctionCall()
8686
// Assert
8787
var assistantMessage = result as AssistantChatMessage;
8888
Assert.NotNull(assistantMessage);
89-
Assert.Equal("test-content", assistantMessage.Content[0].Text);
89+
Assert.Empty(assistantMessage.Content);
9090
// TODO: Uncomment when participant name issue is resolved.
9191
//Assert.Equal("test-name", assistantMessage.ParticipantName);
92-
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments);
92+
Assert.Equal("test-arg1", assistantMessage.FunctionCall.FunctionArguments.ToString());
9393
Assert.Equal("test-name", assistantMessage.FunctionCall.FunctionName);
9494
}
9595

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

118118
Assert.Single(assistantMessage.ToolCalls);
119119
ChatToolCall toolCall = assistantMessage.ToolCalls[0];
120120
Assert.NotNull(toolCall);
121121
Assert.Equal("test-id", toolCall.Id);
122122
Assert.Equal("test-tool-name", toolCall.FunctionName);
123-
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments);
123+
Assert.Equal("test-tool-arg1", toolCall.FunctionArguments.ToString());
124124
}
125125

126126
[Fact]
@@ -198,7 +198,7 @@ public void Test_ChatCompletionsToolCall_ToFunctionToolCall()
198198
Assert.NotNull(chatToolCall);
199199
Assert.Equal("test-id", chatToolCall.Id);
200200
Assert.Equal("test-name", chatToolCall.FunctionName);
201-
Assert.Equal("test-arg1", chatToolCall.FunctionArguments);
201+
Assert.Equal("test-arg1", chatToolCall.FunctionArguments.ToString());
202202
}
203203

204204
[Fact]

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/Models/OpenAIModelTests.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,33 @@ public void Test_Constructor_OpenAI()
3333
new OpenAIModel(options);
3434
}
3535

36+
[Fact]
37+
public void Test_SetMaxTokens()
38+
{
39+
// Arrange
40+
var options = new OpenAIModelOptions("test-key", "test-model");
41+
var chatCompletionOptions = new ChatCompletionOptions();
42+
var model = new OpenAIModel(options);
43+
var testTokens = 100;
44+
45+
// Act
46+
model.SetMaxTokens(testTokens, chatCompletionOptions);
47+
48+
// Assert
49+
MethodInfo info = chatCompletionOptions.GetType().GetMethod("get__deprecatedMaxTokens", BindingFlags.NonPublic | BindingFlags.Instance)!;
50+
int maxTokens = (int)info.Invoke(chatCompletionOptions, null)!;
51+
Assert.Equal(testTokens, maxTokens);
52+
}
53+
54+
3655
[Fact]
3756
public void Test_Constructor_AzureOpenAI_InvalidAzureApiVersion()
3857
{
3958
// Arrange
4059
var options = new AzureOpenAIModelOptions("test-key", "test-deployment", "https://test.openai.azure.com/");
4160
var versions = new List<string>
4261
{
43-
"2024-04-01-preview", "2024-05-01-preview", "2024-06-01"
62+
"2024-06-01", "2024-08-01-preview", "2024-10-01-preview"
4463
};
4564

4665
// Act
@@ -279,8 +298,8 @@ public async Task Test_CompletePromptAsync_AzureOpenAI_Chat_WithTools()
279298

280299
Assert.NotNull(result.Message.ActionCalls);
281300
Assert.Single(result.Message.ActionCalls);
282-
Assert.Equal("testAction", result.Message.ActionCalls[0].Function.Name);
283-
301+
Assert.Equal("testAction", result.Message.ActionCalls[0].Function!.Name);
302+
284303
Assert.Null(result.Error);
285304
Assert.Equal(ChatRole.Assistant, result.Message.Role);
286305
Assert.Null(result.Message.Content);
@@ -326,7 +345,7 @@ public async Task Test_CompletePromptAsync_AzureOpenAI_Streaming()
326345
]
327346
}}"));
328347

329-
TestAsyncResultCollection<StreamingChatCompletionUpdate> updates = new(update!, Mock.Of<PipelineResponse>());
348+
TestAsyncCollectionResult<StreamingChatCompletionUpdate> updates = new(update!, Mock.Of<PipelineResponse>());
330349

331350
var response = new TestResponse(200, string.Empty);
332351
clientMock.Setup((client) =>

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/AITests/OpenAIEmbeddingsTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task Test_OpenAI_CreateEmbeddings_ReturnEmbeddings()
3737
IList<string> inputs = new List<string> { "test" };
3838
var clientMock = new Mock<OpenAIClient>(new ApiKeyCredential(apiKey), It.IsAny<OpenAIClientOptions>());
3939
var response = new TestResponse(200, string.Empty);
40-
var embeddingCollection = ModelReaderWriter.Read<EmbeddingCollection>(BinaryData.FromString(@"{
40+
var embeddingCollection = ModelReaderWriter.Read<OpenAIEmbeddingCollection>(BinaryData.FromString(@"{
4141
""data"": [
4242
{
4343
""object"": ""embedding"",
@@ -76,7 +76,7 @@ public async Task Test_AzureOpenAI_CreateEmbeddings_ReturnEmbeddings()
7676
IList<string> inputs = new List<string> { "test" };
7777
var clientMock = new Mock<OpenAIClient>(new ApiKeyCredential(apiKey), It.IsAny<OpenAIClientOptions>());
7878
var response = new TestResponse(200, string.Empty);
79-
var embeddingCollection = ModelReaderWriter.Read<EmbeddingCollection>(BinaryData.FromString(@"{
79+
var embeddingCollection = ModelReaderWriter.Read<OpenAIEmbeddingCollection>(BinaryData.FromString(@"{
8080
""data"": [
8181
{
8282
""object"": ""embedding"",

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI.Tests/Application/StreamingResponseTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
using AdaptiveCards;
33
using Microsoft.Bot.Builder;
44
using Microsoft.Bot.Schema;
5+
using Microsoft.Teams.AI.AI.Action;
6+
using Microsoft.Teams.AI.AI.Models;
57
using Microsoft.Teams.AI.Application;
68
using Microsoft.Teams.AI.Exceptions;
79
using Microsoft.Teams.AI.Tests.TestUtils;
10+
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
11+
using Moq;
812

913
namespace Microsoft.Teams.AI.Tests.Application
1014
{
@@ -196,6 +200,37 @@ void CaptureSend(Activity[] arg)
196200
Assert.Equal(2, streamer.UpdatesSent());
197201
}
198202

203+
[Fact]
204+
public async Task Test_SendTextChunk_SendsFinalMessageWithPoweredByAIFeatures()
205+
{
206+
// Arrange
207+
Activity[]? activitiesToSend = null;
208+
void CaptureSend(Activity[] arg)
209+
{
210+
activitiesToSend = arg;
211+
}
212+
var adapter = new SimpleAdapter(CaptureSend);
213+
ITurnContext turnContext = new TurnContext(adapter, new Activity(
214+
text: "hello",
215+
channelId: "channelId",
216+
recipient: new() { Id = "recipientId" },
217+
conversation: new() { Id = "conversationId" },
218+
from: new() { Id = "fromId" }
219+
));
220+
StreamingResponse streamer = new(turnContext);
221+
List<Citation> citations = new List<Citation>();
222+
citations.Add(new Citation(content: "test-content", title: "test", url: "https://example.com"));
223+
streamer.QueueTextChunk("first", citations);
224+
await streamer.WaitForQueue();
225+
streamer.QueueTextChunk("second");
226+
await streamer.WaitForQueue();
227+
streamer.EnableFeedbackLoop = true;
228+
streamer.EnableGeneratedByAILabel = true;
229+
streamer.SensitivityLabel = new SensitivityUsageInfo() { Name= "Sensitivity"};
230+
await streamer.EndStream();
231+
Assert.Equal(2, streamer.UpdatesSent());
232+
}
233+
199234
[Fact]
200235
public async Task Test_SendTextChunk_SendsFinalMessageWithAttachments()
201236
{
@@ -233,6 +268,32 @@ void CaptureSend(Activity[] arg)
233268
await streamer.EndStream();
234269
Assert.Equal(2, streamer.UpdatesSent());
235270
Assert.Single(streamer.Attachments);
271+
if (streamer.Citations != null)
272+
{
273+
Assert.Empty(streamer.Citations);
274+
}
275+
}
276+
277+
[Fact]
278+
public async Task Test_SendActivityThrowsException_AssertThrows()
279+
{
280+
// Arrange
281+
Activity[]? activitiesToSend = null;
282+
void CaptureSend(Activity[] arg)
283+
{
284+
activitiesToSend = arg;
285+
}
286+
var adapter = new SimpleAdapter(CaptureSend);
287+
var turnContextMock = new Mock<ITurnContext>();
288+
turnContextMock.Setup((tc) => tc.SendActivityAsync(It.IsAny<Activity>(), It.IsAny<CancellationToken>())).ThrowsAsync(new Exception("Forbidden operation"));
289+
290+
// Act
291+
StreamingResponse streamer = new(turnContextMock.Object);
292+
Exception ex = await Assert.ThrowsAsync<TeamsAIException>(() => streamer.EndStream());
293+
294+
295+
// Assert
296+
Assert.Equal("Error occurred when sending activity while streaming", ex.Message);
236297
}
237298
}
238299
}

0 commit comments

Comments
 (0)