chore: import upstream snapshot with attribution
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="AuthorRole"/>.
|
||||
/// </summary>
|
||||
internal static class AuthorRoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="AuthorRole"/> to a <see cref="Role"/>.
|
||||
/// </summary>
|
||||
/// <param name="role">The author role to convert.</param>
|
||||
/// <returns>The corresponding <see cref="Role"/>.</returns>
|
||||
public static Role ToMCPRole(this AuthorRole role)
|
||||
{
|
||||
if (role == AuthorRole.User)
|
||||
{
|
||||
return Role.User;
|
||||
}
|
||||
|
||||
if (role == AuthorRole.Assistant)
|
||||
{
|
||||
return Role.Assistant;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unexpected role '{role}'");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.SemanticKernel;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ChatMessageContent"/>.
|
||||
/// </summary>
|
||||
public static class ChatMessageContentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ChatMessageContent"/> to a <see cref="CreateMessageResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="chatMessageContent">The <see cref="ChatMessageContent"/> to convert.</param>
|
||||
/// <returns>The corresponding <see cref="CreateMessageResult"/>.</returns>
|
||||
public static CreateMessageResult ToCreateMessageResult(this ChatMessageContent chatMessageContent)
|
||||
{
|
||||
// Using the same heuristic as in the original MCP SDK code: McpClientExtensions.ToCreateMessageResult for consistency.
|
||||
// ChatMessageContent can contain multiple items of different modalities, while the CreateMessageResult
|
||||
// can only have a single content type: text, image, or audio. First, look for image or audio content,
|
||||
// and if not found, fall back to the text content type by concatenating the text of all text contents.
|
||||
ContentBlock? content = null;
|
||||
|
||||
foreach (KernelContent item in chatMessageContent.Items)
|
||||
{
|
||||
if (item is ImageContent image)
|
||||
{
|
||||
content = new ImageContentBlock
|
||||
{
|
||||
Data = Convert.ToBase64String(image.Data!.Value.Span),
|
||||
MimeType = image.MimeType ?? "image/jpeg"
|
||||
};
|
||||
break;
|
||||
}
|
||||
else if (item is AudioContent audio)
|
||||
{
|
||||
content = new AudioContentBlock
|
||||
{
|
||||
Data = Convert.ToBase64String(audio.Data!.Value.Span),
|
||||
MimeType = audio.MimeType ?? "audio/mpeg"
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
content ??= new TextContentBlock
|
||||
{
|
||||
Text = string.Concat(chatMessageContent.Items.OfType<TextContent>()),
|
||||
};
|
||||
|
||||
return new CreateMessageResult
|
||||
{
|
||||
Role = chatMessageContent.Role.ToMCPRole(),
|
||||
Model = chatMessageContent.ModelId ?? "unknown",
|
||||
Content = content
|
||||
};
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="ContentBlock"/> class.
|
||||
/// </summary>
|
||||
public static class ContentBlockExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ContentBlock"/> object to a <see cref="KernelContent"/> object.
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="ContentBlock"/> object to convert.</param>
|
||||
/// <returns>The corresponding <see cref="KernelContent"/> object.</returns>
|
||||
public static KernelContent ToKernelContent(this ContentBlock content)
|
||||
{
|
||||
return content switch
|
||||
{
|
||||
TextContentBlock textContentBlock => new TextContent(textContentBlock.Text),
|
||||
ImageContentBlock imageContentBlock => new ImageContent(Convert.FromBase64String(imageContentBlock.Data!), imageContentBlock.MimeType),
|
||||
AudioContentBlock audioContentBlock => new AudioContent(Convert.FromBase64String(audioContentBlock.Data!), audioContentBlock.MimeType),
|
||||
_ => throw new InvalidOperationException($"Unexpected message content type '{content.Type}'"),
|
||||
};
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="GetPromptResult"/>.
|
||||
/// </summary>
|
||||
internal static class PromptResultExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="GetPromptResult"/> to chat message contents.
|
||||
/// </summary>
|
||||
/// <param name="result">The prompt result to convert.</param>
|
||||
/// <returns>The corresponding <see cref="ChatHistory"/>.</returns>
|
||||
public static IList<ChatMessageContent> ToChatMessageContents(this GetPromptResult result)
|
||||
{
|
||||
return [.. result.Messages.Select(ToChatMessageContent)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="PromptMessage"/> to a <see cref="ChatMessageContent"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">The <see cref="PromptMessage"/> to convert.</param>
|
||||
/// <returns>The corresponding <see cref="ChatMessageContent"/>.</returns>
|
||||
public static ChatMessageContent ToChatMessageContent(this PromptMessage message)
|
||||
{
|
||||
return new ChatMessageContent(role: message.Role.ToAuthorRole(), items: [message.Content.ToKernelContent()]);
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ReadResourceResult"/>.
|
||||
/// </summary>
|
||||
public static class ReadResourceResultExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ReadResourceResult"/> to a <see cref="ChatMessageContentItemCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="readResourceResult">The MCP read resource result to convert.</param>
|
||||
/// <returns>The corresponding <see cref="ChatMessageContentItemCollection"/>.</returns>
|
||||
public static ChatMessageContentItemCollection ToChatMessageContentItemCollection(this ReadResourceResult readResourceResult)
|
||||
{
|
||||
if (readResourceResult.Contents.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("The resource does not contain any contents.");
|
||||
}
|
||||
|
||||
ChatMessageContentItemCollection result = [];
|
||||
|
||||
foreach (var resourceContent in readResourceResult.Contents)
|
||||
{
|
||||
Dictionary<string, object?> metadata = new()
|
||||
{
|
||||
["uri"] = resourceContent.Uri
|
||||
};
|
||||
|
||||
if (resourceContent is TextResourceContents textResourceContent)
|
||||
{
|
||||
result.Add(new TextContent()
|
||||
{
|
||||
Text = textResourceContent.Text,
|
||||
MimeType = textResourceContent.MimeType,
|
||||
Metadata = metadata,
|
||||
});
|
||||
}
|
||||
else if (resourceContent is BlobResourceContents blobResourceContent)
|
||||
{
|
||||
if (blobResourceContent.MimeType?.StartsWith("image", System.StringComparison.InvariantCulture) ?? false)
|
||||
{
|
||||
result.Add(new ImageContent()
|
||||
{
|
||||
Data = Convert.FromBase64String(blobResourceContent.Blob),
|
||||
MimeType = blobResourceContent.MimeType,
|
||||
Metadata = metadata,
|
||||
});
|
||||
}
|
||||
else if (blobResourceContent.MimeType?.StartsWith("audio", System.StringComparison.InvariantCulture) ?? false)
|
||||
{
|
||||
result.Add(new AudioContent
|
||||
{
|
||||
Data = Convert.FromBase64String(blobResourceContent.Blob),
|
||||
MimeType = blobResourceContent.MimeType,
|
||||
Metadata = metadata,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(new BinaryContent
|
||||
{
|
||||
Data = Convert.FromBase64String(blobResourceContent.Blob),
|
||||
MimeType = blobResourceContent.MimeType,
|
||||
Metadata = metadata,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="Role"/> enum.
|
||||
/// </summary>
|
||||
internal static class RoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Role"/> to a <see cref="AuthorRole"/>.
|
||||
/// </summary>
|
||||
/// <param name="role">The MCP role to convert.</param>
|
||||
/// <returns>The corresponding <see cref="AuthorRole"/>.</returns>
|
||||
public static AuthorRole ToAuthorRole(this Role role)
|
||||
{
|
||||
return role switch
|
||||
{
|
||||
Role.User => AuthorRole.User,
|
||||
Role.Assistant => AuthorRole.Assistant,
|
||||
_ => throw new InvalidOperationException($"Unexpected role '{role}'")
|
||||
};
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.SemanticKernel;
|
||||
using ModelContextProtocol.Protocol;
|
||||
|
||||
namespace MCPClient;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="SamplingMessage"/>.
|
||||
/// </summary>
|
||||
public static class SamplingMessageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a collection of <see cref="SamplingMessage"/> to a list of <see cref="ChatMessageContent"/>.
|
||||
/// </summary>
|
||||
/// <param name="samplingMessages">The collection of <see cref="SamplingMessage"/> to convert.</param>
|
||||
/// <returns>The corresponding list of <see cref="ChatMessageContent"/>.</returns>
|
||||
public static List<ChatMessageContent> ToChatMessageContents(this IEnumerable<SamplingMessage> samplingMessages)
|
||||
{
|
||||
return [.. samplingMessages.Select(ToChatMessageContent)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="SamplingMessage"/> to a <see cref="ChatMessageContent"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">The <see cref="SamplingMessage"/> to convert.</param>
|
||||
/// <returns>The corresponding <see cref="ChatMessageContent"/>.</returns>
|
||||
public static ChatMessageContent ToChatMessageContent(this SamplingMessage message)
|
||||
{
|
||||
return new ChatMessageContent(role: message.Role.ToAuthorRole(), items: [message.Content.ToKernelContent()]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user