forked from modelcontextprotocol/csharp-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAIContentExtensions.cs
More file actions
136 lines (118 loc) · 5.38 KB
/
AIContentExtensions.cs
File metadata and controls
136 lines (118 loc) · 5.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using Microsoft.Extensions.AI;
using ModelContextProtocol.Protocol.Types;
using ModelContextProtocol.Utils;
using ModelContextProtocol.Utils.Json;
using System.Runtime.InteropServices;
using System.Text.Json;
namespace ModelContextProtocol;
/// <summary>Provides helpers for conversions related to <see cref="AIContent"/>.</summary>
public static class AIContentExtensions
{
/// <summary>Creates a <see cref="ChatMessage"/> from a <see cref="PromptMessage"/>.</summary>
/// <param name="promptMessage">The message to convert.</param>
/// <returns>The created <see cref="ChatMessage"/>.</returns>
public static ChatMessage ToChatMessage(this PromptMessage promptMessage)
{
Throw.IfNull(promptMessage);
return new()
{
RawRepresentation = promptMessage,
Role = promptMessage.Role == Role.User ? ChatRole.User : ChatRole.Assistant,
Contents = [ToAIContent(promptMessage.Content)]
};
}
/// <summary>Creates a new <see cref="AIContent"/> from the content of a <see cref="Content"/>.</summary>
/// <param name="content">The <see cref="Content"/> to convert.</param>
/// <returns>The created <see cref="AIContent"/>.</returns>
public static AIContent ToAIContent(this Content content)
{
Throw.IfNull(content);
AIContent ac;
if (content is { Type: "image", MimeType: not null, Data: not null })
{
ac = new DataContent(Convert.FromBase64String(content.Data), content.MimeType);
}
else if (content is { Type: "resource" } && content.Resource is { } resourceContents)
{
ac = resourceContents.Blob is not null && resourceContents.MimeType is not null ?
new DataContent(Convert.FromBase64String(resourceContents.Blob), resourceContents.MimeType) :
new TextContent(resourceContents.Text);
(ac.AdditionalProperties ??= [])["uri"] = resourceContents.Uri;
}
else
{
ac = new TextContent(content.Text);
}
ac.RawRepresentation = content;
return ac;
}
/// <summary>Creates a new <see cref="AIContent"/> from the content of a <see cref="ResourceContents"/>.</summary>
/// <param name="content">The <see cref="ResourceContents"/> to convert.</param>
/// <returns>The created <see cref="AIContent"/>.</returns>
public static AIContent ToAIContent(this ResourceContents content)
{
Throw.IfNull(content);
AIContent ac = content.Blob is not null && content.MimeType is not null ?
new DataContent(Convert.FromBase64String(content.Blob), content.MimeType) :
new TextContent(content.Text);
(ac.AdditionalProperties ??= [])["uri"] = content.Uri;
ac.RawRepresentation = content;
return ac;
}
/// <summary>Creates a list of <see cref="AIContent"/> from a sequence of <see cref="Content"/>.</summary>
/// <param name="contents">The <see cref="Content"/> instances to convert.</param>
/// <returns>The created <see cref="AIContent"/> instances.</returns>
public static IList<AIContent> ToAIContents(this IEnumerable<Content> contents)
{
Throw.IfNull(contents);
return contents.Select(ToAIContent).ToList();
}
/// <summary>Creates a list of <see cref="AIContent"/> from a sequence of <see cref="ResourceContents"/>.</summary>
/// <param name="contents">The <see cref="ResourceContents"/> instances to convert.</param>
/// <returns>The created <see cref="AIContent"/> instances.</returns>
public static IList<AIContent> ToAIContents(this IEnumerable<ResourceContents> contents)
{
Throw.IfNull(contents);
return contents.Select(ToAIContent).ToList();
}
/// <summary>Extracts the data from a <see cref="DataContent"/> as a Base64 string.</summary>
internal static string GetBase64Data(this DataContent dataContent)
{
#if NET
return Convert.ToBase64String(dataContent.Data.Span);
#else
return MemoryMarshal.TryGetArray(dataContent.Data, out ArraySegment<byte> segment) ?
Convert.ToBase64String(segment.Array!, segment.Offset, segment.Count) :
Convert.ToBase64String(dataContent.Data.ToArray());
#endif
}
/// <summary>
/// Converts different types of <see cref="AIContent"/> into a standardized <see cref="Content"/> object with specific properties based on the
/// content type.
/// </summary>
/// <param name="content"></param>
/// <returns>A <see cref="Content"/> object that encapsulates the relevant properties derived from the input content.</returns>
public static Content ToContent(this AIContent content) =>
content switch
{
TextContent textContent => new()
{
Text = textContent.Text,
Type = "text",
},
DataContent dataContent => new()
{
Data = dataContent.GetBase64Data(),
MimeType = dataContent.MediaType,
Type =
dataContent.HasTopLevelMediaType("image") ? "image" :
dataContent.HasTopLevelMediaType("audio") ? "audio" :
"resource",
},
_ => new()
{
Text = JsonSerializer.Serialize(content, McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object))),
Type = "text",
}
};
}