Add tools support to sampling (#976)
This commit is contained in:
parent
ad86b53347
commit
15139cc569
4 changed files with 1623 additions and 425 deletions
|
|
@ -249,7 +249,7 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
{
|
||||
AIContent aiContent => new()
|
||||
{
|
||||
Content = [aiContent.ToContent()],
|
||||
Content = [aiContent.ToContentBlock()],
|
||||
StructuredContent = structuredContent,
|
||||
IsError = aiContent is ErrorContent
|
||||
},
|
||||
|
|
@ -491,7 +491,7 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool
|
|||
|
||||
foreach (var item in contentItems)
|
||||
{
|
||||
contentList.Add(item.ToContent());
|
||||
contentList.Add(item.ToContentBlock());
|
||||
hasAny = true;
|
||||
|
||||
if (allErrorContent && item is not ErrorContent)
|
||||
|
|
|
|||
|
|
@ -106,42 +106,26 @@ public abstract partial class McpServer : McpSession, IMcpServer
|
|||
continue;
|
||||
}
|
||||
|
||||
if (message.Role == ChatRole.User || message.Role == ChatRole.Assistant)
|
||||
Role role = message.Role == ChatRole.Assistant ? Role.Assistant : Role.User;
|
||||
|
||||
// Group all content blocks from this message into a single SamplingMessage
|
||||
List<ContentBlock> contentBlocks = [];
|
||||
foreach (var content in message.Contents)
|
||||
{
|
||||
Role role = message.Role == ChatRole.User ? Role.User : Role.Assistant;
|
||||
|
||||
foreach (var content in message.Contents)
|
||||
if (content.ToContentBlock() is { } contentBlock)
|
||||
{
|
||||
switch (content)
|
||||
{
|
||||
case TextContent textContent:
|
||||
samplingMessages.Add(new()
|
||||
{
|
||||
Role = role,
|
||||
Content = new TextContentBlock { Text = textContent.Text },
|
||||
});
|
||||
break;
|
||||
|
||||
case DataContent dataContent when dataContent.HasTopLevelMediaType("image") || dataContent.HasTopLevelMediaType("audio"):
|
||||
samplingMessages.Add(new()
|
||||
{
|
||||
Role = role,
|
||||
Content = dataContent.HasTopLevelMediaType("image") ?
|
||||
new ImageContentBlock
|
||||
{
|
||||
MimeType = dataContent.MediaType,
|
||||
Data = dataContent.Base64Data.ToString(),
|
||||
} :
|
||||
new AudioContentBlock
|
||||
{
|
||||
MimeType = dataContent.MediaType,
|
||||
Data = dataContent.Base64Data.ToString(),
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
contentBlocks.Add(contentBlock);
|
||||
}
|
||||
}
|
||||
|
||||
if (contentBlocks.Count > 0)
|
||||
{
|
||||
samplingMessages.Add(new()
|
||||
{
|
||||
Role = role,
|
||||
Content = contentBlocks,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ModelPreferences? modelPreferences = null;
|
||||
|
|
@ -150,25 +134,63 @@ public abstract partial class McpServer : McpSession, IMcpServer
|
|||
modelPreferences = new() { Hints = [new() { Name = modelId }] };
|
||||
}
|
||||
|
||||
IList<Tool>? tools = null;
|
||||
if (options?.Tools is { Count: > 0 })
|
||||
{
|
||||
foreach (var tool in options.Tools)
|
||||
{
|
||||
if (tool is AIFunctionDeclaration af)
|
||||
{
|
||||
(tools ??= []).Add(new()
|
||||
{
|
||||
Name = af.Name,
|
||||
Description = af.Description,
|
||||
InputSchema = af.JsonSchema,
|
||||
Meta = af.AdditionalProperties.ToJsonObject(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolChoice? toolChoice = options?.ToolMode switch
|
||||
{
|
||||
NoneChatToolMode => new() { Mode = ToolChoice.ModeNone },
|
||||
AutoChatToolMode => new() { Mode = ToolChoice.ModeAuto },
|
||||
RequiredChatToolMode => new() { Mode = ToolChoice.ModeRequired },
|
||||
_ => null,
|
||||
};
|
||||
|
||||
var result = await SampleAsync(new()
|
||||
{
|
||||
Messages = samplingMessages,
|
||||
MaxTokens = options?.MaxOutputTokens ?? ServerOptions.MaxSamplingOutputTokens,
|
||||
Messages = samplingMessages,
|
||||
ModelPreferences = modelPreferences,
|
||||
StopSequences = options?.StopSequences?.ToArray(),
|
||||
SystemPrompt = systemPrompt?.ToString(),
|
||||
Temperature = options?.Temperature,
|
||||
ModelPreferences = modelPreferences,
|
||||
ToolChoice = toolChoice,
|
||||
Tools = tools,
|
||||
Meta = options?.AdditionalProperties?.ToJsonObject(),
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
AIContent? responseContent = result.Content.ToAIContent();
|
||||
List<AIContent> responseContents = [];
|
||||
foreach (var block in result.Content)
|
||||
{
|
||||
if (block.ToAIContent() is { } content)
|
||||
{
|
||||
responseContents.Add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return new(new ChatMessage(result.Role is Role.User ? ChatRole.User : ChatRole.Assistant, responseContent is not null ? [responseContent] : []))
|
||||
return new(new ChatMessage(result.Role is Role.User ? ChatRole.User : ChatRole.Assistant, responseContents))
|
||||
{
|
||||
ModelId = result.Model,
|
||||
FinishReason = result.StopReason switch
|
||||
{
|
||||
"maxTokens" => ChatFinishReason.Length,
|
||||
"endTurn" or "stopSequence" or _ => ChatFinishReason.Stop,
|
||||
CreateMessageResult.StopReasonMaxTokens => ChatFinishReason.Length,
|
||||
CreateMessageResult.StopReasonToolUse => ChatFinishReason.ToolCalls,
|
||||
CreateMessageResult.StopReasonEndTurn or CreateMessageResult.StopReasonStopSequence => ChatFinishReason.Stop,
|
||||
_ => null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ namespace ModelContextProtocol.Server;
|
|||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="AIContent"/></term>
|
||||
/// <description>Converted to a single <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContent(AIContent)"/>.</description>
|
||||
/// <description>Converted to a single <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContentBlock(AIContent)"/>.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="string"/></term>
|
||||
|
|
@ -111,7 +111,7 @@ namespace ModelContextProtocol.Server;
|
|||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="IEnumerable{AIContent}"/> of <see cref="AIContent"/></term>
|
||||
/// <description>Each <see cref="AIContent"/> is converted to a <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContent(AIContent)"/>.</description>
|
||||
/// <description>Each <see cref="AIContent"/> is converted to a <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContentBlock(AIContent)"/>.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="IEnumerable{ContentBlock}"/> of <see cref="ContentBlock"/></term>
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ namespace ModelContextProtocol.Server;
|
|||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="AIContent"/></term>
|
||||
/// <description>Converted to a single <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContent(AIContent)"/>.</description>
|
||||
/// <description>Converted to a single <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContentBlock(AIContent)"/>.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="string"/></term>
|
||||
|
|
@ -106,7 +106,7 @@ namespace ModelContextProtocol.Server;
|
|||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="IEnumerable{AIContent}"/> of <see cref="AIContent"/></term>
|
||||
/// <description>Each <see cref="AIContent"/> is converted to a <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContent(AIContent)"/>.</description>
|
||||
/// <description>Each <see cref="AIContent"/> is converted to a <see cref="ContentBlock"/> object using <see cref="AIContentExtensions.ToContentBlock(AIContent)"/>.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see cref="IEnumerable{Content}"/> of <see cref="ContentBlock"/></term>
|
||||
|
|
|
|||
Loading…
Reference in a new issue