-
Notifications
You must be signed in to change notification settings - Fork 4k
.Net: SK integration with MEAI Abstractions (Service Selector + Contents) Phase 1 #10651
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
RogerBarreto
merged 31 commits into
microsoft:feature-msextensions-ai
from
RogerBarreto:issues/10319-sk-meai-integration
Mar 3, 2025
Merged
Changes from 15 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
2411de2
Service Selector investigation
RogerBarreto e980d1b
MEAI integration chatclient kernel service selector
RogerBarreto 4e82956
Update UT
RogerBarreto fdcf588
WIP
RogerBarreto 8911ca6
UT for IChatClient service selector WIP
RogerBarreto ff00e14
Undo change
RogerBarreto 0232073
Fix warnings
RogerBarreto 79341db
UT passing OrderedServiceSelector
RogerBarreto d29ca14
Ensure kernel.Invoke can return MEAI.Contents
RogerBarreto e73fad7
Adding bidirectional content support
RogerBarreto 26e3cbb
Content Permutations UT
RogerBarreto 19dab90
Ensure types converge
RogerBarreto 92d7b49
Fix warnings
RogerBarreto 1bd07fd
Reducing public apis
RogerBarreto d82f7ea
Add suppressions
RogerBarreto 66d3f0a
Address PR comments
RogerBarreto 4071341
Addressed Selector comments
RogerBarreto e2fdba6
Added integration tests
RogerBarreto 02ed447
GptAIServiceSelector
RogerBarreto 1f6bd8b
Add experimental + fixes
RogerBarreto 2d4b08f
Fix UT Agents
RogerBarreto 7a50f09
Fix usings
RogerBarreto f26bffb
Address PR Feedback
RogerBarreto bb35f00
Fix warnings
RogerBarreto 38724da
Fix warnings
RogerBarreto 4bc6b63
Fix warnings
RogerBarreto b188434
Adding missing UT, addresssing Review feedback
RogerBarreto 178be40
Add missing UT
RogerBarreto d2588bb
Fix warnings
RogerBarreto b70d35e
Warning fix + UT
RogerBarreto c7fb8cd
Fix GptSelector
RogerBarreto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 0 additions & 3 deletions
3
dotnet/src/Experimental/Process.IntegrationTests.Shared/ProcessCloudEventsTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 0 additions & 2 deletions
2
dotnet/src/Experimental/Process.IntegrationTests.Shared/ProcessTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
dotnet/src/SemanticKernel.Abstractions/AI/ChatClient/ChatClientAIService.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.AI; | ||
using Microsoft.SemanticKernel.Services; | ||
|
||
namespace Microsoft.SemanticKernel.AI.ChatCompletion; | ||
|
||
/// <summary> | ||
/// Allow <see cref="IChatClient"/> to be used as an <see cref="IAIService"/> in a <see cref="IAIServiceSelector"/> | ||
/// </summary> | ||
internal sealed class ChatClientAIService : IAIService, IChatClient | ||
{ | ||
private readonly IChatClient _chatClient; | ||
|
||
/// <summary> | ||
/// Storage for AI service attributes. | ||
/// </summary> | ||
internal Dictionary<string, object?> _internalAttributes { get; } = []; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ChatClientAIService"/> class. | ||
/// </summary> | ||
/// <param name="chatClient">Target <see cref="IChatClient"/>.</param> | ||
internal ChatClientAIService(IChatClient chatClient) | ||
{ | ||
Verify.NotNull(chatClient); | ||
this._chatClient = chatClient; | ||
|
||
var metadata = this._chatClient.GetService<ChatClientMetadata>(); | ||
Verify.NotNull(metadata); | ||
|
||
this._internalAttributes[nameof(metadata.ModelId)] = metadata.ModelId; | ||
this._internalAttributes[nameof(metadata.ProviderName)] = metadata.ProviderName; | ||
this._internalAttributes[nameof(metadata.ProviderUri)] = metadata.ProviderUri; | ||
} | ||
|
||
/// <inheritdoc /> | ||
public IReadOnlyDictionary<string, object?> Attributes => this._internalAttributes; | ||
|
||
/// <inheritdoc /> | ||
public void Dispose() => this._chatClient.Dispose(); | ||
|
||
/// <inheritdoc /> | ||
public Task<ChatResponse> GetResponseAsync(IList<ChatMessage> chatMessages, ChatOptions? options = null, CancellationToken cancellationToken = default) | ||
=> this._chatClient.GetResponseAsync(chatMessages, options, cancellationToken); | ||
|
||
/// <inheritdoc /> | ||
public object? GetService(Type serviceType, object? serviceKey = null) | ||
=> this._chatClient.GetService(serviceType, serviceKey); | ||
|
||
/// <inheritdoc /> | ||
public IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(IList<ChatMessage> chatMessages, ChatOptions? options = null, CancellationToken cancellationToken = default) | ||
=> this._chatClient.GetStreamingResponseAsync(chatMessages, options, cancellationToken); | ||
} |
73 changes: 73 additions & 0 deletions
73
dotnet/src/SemanticKernel.Abstractions/AI/ChatClient/ChatClientExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.AI; | ||
|
||
namespace Microsoft.SemanticKernel.ChatCompletion; | ||
|
||
/// <summary> | ||
/// Class sponsor that holds extension methods for <see cref="IChatClient"/> interface. | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// </summary> | ||
public static class ChatClientExtensions | ||
{ | ||
/// <summary> | ||
/// Get chat multiple chat message content choices for the prompt and settings. | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// </summary> | ||
/// <remarks> | ||
/// This should be used when the settings request for more than one choice. | ||
/// </remarks> | ||
/// <param name="chatClient">Target chat client service.</param> | ||
/// <param name="prompt">The standardized prompt input.</param> | ||
/// <param name="executionSettings">The AI execution settings (optional).</param> | ||
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param> | ||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param> | ||
/// <returns>List of different chat message content choices generated by the remote model</returns> | ||
internal static Task<ChatResponse> GetResponseAsync( | ||
this IChatClient chatClient, | ||
string prompt, | ||
PromptExecutionSettings? executionSettings = null, | ||
Kernel? kernel = null, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
var chatOptions = executionSettings.ToChatOptions(kernel); | ||
|
||
// Try to parse the text as a chat history | ||
if (ChatPromptParser.TryParse(prompt, out var chatHistoryFromPrompt)) | ||
{ | ||
var messageList = chatHistoryFromPrompt.ToChatMessageList(); | ||
return chatClient.GetResponseAsync(messageList, chatOptions, cancellationToken); | ||
} | ||
|
||
return chatClient.GetResponseAsync(prompt, chatOptions, cancellationToken); | ||
} | ||
|
||
/// <summary>Creates an <see cref="IChatCompletionService"/> for the specified <see cref="IChatClient"/>.</summary> | ||
/// <param name="client">The chat client to be represented as a chat completion service.</param> | ||
/// <param name="serviceProvider">An optional <see cref="IServiceProvider"/> that can be used to resolve services to use in the instance.</param> | ||
/// <returns> | ||
/// The <see cref="IChatCompletionService"/>. If <paramref name="client"/> is an <see cref="IChatCompletionService"/>, <paramref name="client"/> will | ||
/// be returned. Otherwise, a new <see cref="IChatCompletionService"/> will be created that wraps <paramref name="client"/>. | ||
/// </returns> | ||
[Experimental("SKEXP0001")] | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public static IChatCompletionService AsChatCompletionService(this IChatClient client, IServiceProvider? serviceProvider = null) | ||
{ | ||
Verify.NotNull(client); | ||
|
||
return client is IChatCompletionService chatCompletionService ? | ||
chatCompletionService : | ||
new ChatClientChatCompletionService(client, serviceProvider); | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// <summary> | ||
/// Get the model identifier for the specified <see cref="IChatClient"/>. | ||
/// </summary> | ||
public static string? GetModelId(this IChatClient client) | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
Verify.NotNull(client); | ||
|
||
return client.GetService<ChatClientMetadata>()?.ModelId; | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
dotnet/src/SemanticKernel.Abstractions/AI/ChatClient/ChatMessageExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using Microsoft.Extensions.AI; | ||
using Microsoft.SemanticKernel.ChatCompletion; | ||
|
||
namespace Microsoft.SemanticKernel.AI.ChatCompletion; | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
internal static class ChatMessageExtensions | ||
{ | ||
/// <summary>Converts a <see cref="ChatMessage"/> to a <see cref="ChatMessageContent"/>.</summary> | ||
/// <remarks>This conversion should not be necessary once SK eventually adopts the shared content types.</remarks> | ||
internal static ChatMessageContent ToChatMessageContent(this ChatMessage message, ChatResponse? response = null) | ||
RogerBarreto marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
ChatMessageContent result = new() | ||
{ | ||
ModelId = response?.ModelId, | ||
AuthorName = message.AuthorName, | ||
InnerContent = response?.RawRepresentation ?? message.RawRepresentation, | ||
Metadata = message.AdditionalProperties, | ||
Role = new AuthorRole(message.Role.Value), | ||
}; | ||
|
||
foreach (AIContent content in message.Contents) | ||
{ | ||
KernelContent? resultContent = null; | ||
switch (content) | ||
{ | ||
case Microsoft.Extensions.AI.TextContent tc: | ||
resultContent = new Microsoft.SemanticKernel.TextContent(tc.Text); | ||
break; | ||
|
||
case Microsoft.Extensions.AI.DataContent dc when dc.MediaTypeStartsWith("image/"): | ||
resultContent = dc.Data is not null ? | ||
new Microsoft.SemanticKernel.ImageContent(dc.Uri) : | ||
new Microsoft.SemanticKernel.ImageContent(new Uri(dc.Uri)); | ||
break; | ||
|
||
case Microsoft.Extensions.AI.DataContent dc when dc.MediaTypeStartsWith("audio/"): | ||
resultContent = dc.Data is not null ? | ||
new Microsoft.SemanticKernel.AudioContent(dc.Uri) : | ||
new Microsoft.SemanticKernel.AudioContent(new Uri(dc.Uri)); | ||
break; | ||
|
||
case Microsoft.Extensions.AI.DataContent dc: | ||
resultContent = dc.Data is not null ? | ||
new Microsoft.SemanticKernel.BinaryContent(dc.Uri) : | ||
new Microsoft.SemanticKernel.BinaryContent(new Uri(dc.Uri)); | ||
break; | ||
|
||
case Microsoft.Extensions.AI.FunctionCallContent fcc: | ||
resultContent = new Microsoft.SemanticKernel.FunctionCallContent(fcc.Name, null, fcc.CallId, fcc.Arguments is not null ? new(fcc.Arguments) : null); | ||
break; | ||
|
||
case Microsoft.Extensions.AI.FunctionResultContent frc: | ||
resultContent = new Microsoft.SemanticKernel.FunctionResultContent(callId: frc.CallId, result: frc.Result); | ||
break; | ||
} | ||
|
||
if (resultContent is not null) | ||
{ | ||
resultContent.Metadata = content.AdditionalProperties; | ||
resultContent.InnerContent = content.RawRepresentation; | ||
resultContent.ModelId = response?.ModelId; | ||
result.Items.Add(resultContent); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
dotnet/src/SemanticKernel.Abstractions/AI/ChatClient/ChatResponseUpdateExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System.Text.Json; | ||
using Microsoft.Extensions.AI; | ||
|
||
namespace Microsoft.SemanticKernel.ChatCompletion; | ||
|
||
/// <summary>Provides extension methods for <see cref="ChatResponseUpdate"/>.</summary> | ||
internal static class ChatResponseUpdateExtensions | ||
{ | ||
/// <summary>Converts a <see cref="ChatResponseUpdate"/> to a <see cref="StreamingChatMessageContent"/>.</summary> | ||
/// <remarks>This conversion should not be necessary once SK eventually adopts the shared content types.</remarks> | ||
internal static StreamingChatMessageContent ToStreamingChatMessageContent(this ChatResponseUpdate update) | ||
{ | ||
StreamingChatMessageContent content = new( | ||
update.Role is not null ? new AuthorRole(update.Role.Value.Value) : null, | ||
null) | ||
{ | ||
InnerContent = update.RawRepresentation, | ||
ChoiceIndex = update.ChoiceIndex, | ||
Metadata = update.AdditionalProperties, | ||
ModelId = update.ModelId | ||
}; | ||
|
||
foreach (AIContent item in update.Contents) | ||
{ | ||
StreamingKernelContent? resultContent = | ||
item is Microsoft.Extensions.AI.TextContent tc ? new Microsoft.SemanticKernel.StreamingTextContent(tc.Text) : | ||
item is Microsoft.Extensions.AI.FunctionCallContent fcc ? | ||
new Microsoft.SemanticKernel.StreamingFunctionCallUpdateContent(fcc.CallId, fcc.Name, fcc.Arguments is not null ? | ||
JsonSerializer.Serialize(fcc.Arguments!, AbstractionsJsonContext.Default.IDictionaryStringObject!) : | ||
null) : | ||
null; | ||
|
||
if (resultContent is not null) | ||
{ | ||
resultContent.ModelId = update.ModelId; | ||
content.Items.Add(resultContent); | ||
} | ||
} | ||
|
||
return content; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.