mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
.Net: First step in moving to use function calling processor (#9562)
### Motivation and Context First step in updating the MistralAI connector to use the function calling processor ### Description 1. Some code clean up 2. Add the FunctionCallsProcessor ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
This commit is contained in:
@@ -50,7 +50,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
|
||||
// Act
|
||||
var executionSettings = new MistralAIPromptExecutionSettings { MaxTokens = 1024, Temperature = 0.9 };
|
||||
await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings);
|
||||
await client.GetChatMessageContentsAsync(chatHistory, executionSettings);
|
||||
|
||||
// Assert
|
||||
var request = this.DelegatingHandler!.RequestContent;
|
||||
@@ -76,7 +76,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the best French cheese?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -96,7 +96,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
|
||||
// Act
|
||||
List<string> data = ["Hello", "world"];
|
||||
var response = await client.GenerateEmbeddingsAsync(data, default);
|
||||
var response = await client.GenerateEmbeddingsAsync(data);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -117,7 +117,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = client.GetStreamingChatMessageContentsAsync(chatHistory, default);
|
||||
var response = client.GetStreamingChatMessageContentsAsync(chatHistory);
|
||||
var chunks = new List<StreamingChatMessageContent>();
|
||||
await foreach (var chunk in response)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await client.GetChatMessageContentsAsync(chatHistory, default));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await client.GetChatMessageContentsAsync(chatHistory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -161,7 +161,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
var chatHistory = new ChatHistory();
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await client.GetChatMessageContentsAsync(chatHistory, default));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await client.GetChatMessageContentsAsync(chatHistory));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -181,7 +181,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
kernel.Plugins.AddFromType<WeatherPlugin>();
|
||||
|
||||
// Act
|
||||
await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
var request = this.DelegatingHandler!.RequestContent;
|
||||
@@ -212,7 +212,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
|
||||
// Act
|
||||
var executionSettings = new MistralAIPromptExecutionSettings { ToolCallBehavior = MistralAIToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
var response = client.GetStreamingChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = client.GetStreamingChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
var chunks = new List<StreamingChatMessageContent>();
|
||||
await foreach (var chunk in response)
|
||||
{
|
||||
@@ -253,7 +253,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather like in Paris?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -279,7 +279,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather like in Paris?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -307,7 +307,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather like in Paris?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -345,7 +345,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather like in Paris?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -389,11 +389,11 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
|
||||
if (isStreaming)
|
||||
{
|
||||
await client.GetStreamingChatMessageContentsAsync(chatHistory, default, executionSettings, kernel).ToListAsync();
|
||||
await client.GetStreamingChatMessageContentsAsync(chatHistory, executionSettings, kernel).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
}
|
||||
|
||||
// Assert
|
||||
@@ -428,7 +428,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
{
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather like in Paris?")
|
||||
};
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, default, executionSettings, kernel);
|
||||
var response = await client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response);
|
||||
@@ -465,7 +465,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
List<StreamingKernelContent> streamingContent = [];
|
||||
|
||||
// Act
|
||||
await foreach (var item in client.GetStreamingChatMessageContentsAsync(chatHistory, default, executionSettings, kernel))
|
||||
await foreach (var item in client.GetStreamingChatMessageContentsAsync(chatHistory, executionSettings, kernel))
|
||||
{
|
||||
streamingContent.Add(item);
|
||||
}
|
||||
@@ -497,7 +497,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
};
|
||||
|
||||
// Act
|
||||
var messages = client.ToMistralChatMessages(chatMessage, default);
|
||||
var messages = client.ToMistralChatMessages(chatMessage);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(messages);
|
||||
@@ -517,7 +517,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
};
|
||||
|
||||
// Act
|
||||
var messages = client.ToMistralChatMessages(content, default);
|
||||
var messages = client.ToMistralChatMessages(content);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(messages);
|
||||
@@ -537,7 +537,7 @@ public sealed class MistralClientTests : MistralTestBase
|
||||
};
|
||||
|
||||
// Act
|
||||
var messages = client.ToMistralChatMessages(content, default);
|
||||
var messages = client.ToMistralChatMessages(content);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(messages);
|
||||
|
||||
@@ -16,6 +16,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.FunctionCalling;
|
||||
using Microsoft.SemanticKernel.Diagnostics;
|
||||
using Microsoft.SemanticKernel.Http;
|
||||
using Microsoft.SemanticKernel.Text;
|
||||
@@ -27,6 +28,14 @@ namespace Microsoft.SemanticKernel.Connectors.MistralAI.Client;
|
||||
/// </summary>
|
||||
internal sealed class MistralClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an instance of <see cref="MistralClient"/>
|
||||
/// </summary>
|
||||
/// <param name="modelId">The model id</param>
|
||||
/// <param name="httpClient">The HTTP Client</param>
|
||||
/// <param name="apiKey">The API key</param>
|
||||
/// <param name="endpoint">An optional endpoint URI</param>
|
||||
/// <param name="logger">An optional logger</param>
|
||||
internal MistralClient(
|
||||
string modelId,
|
||||
HttpClient httpClient,
|
||||
@@ -44,9 +53,17 @@ internal sealed class MistralClient
|
||||
this._httpClient = httpClient;
|
||||
this._logger = logger ?? NullLogger.Instance;
|
||||
this._streamJsonParser = new StreamJsonParser();
|
||||
this._functionCallsProcessor = new FunctionCallsProcessor(this._logger);
|
||||
}
|
||||
|
||||
internal async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, CancellationToken cancellationToken, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null)
|
||||
/// <summary>
|
||||
/// Generate new chat message responses.
|
||||
/// </summary>
|
||||
/// <param name="chatHistory">Chat history</param>
|
||||
/// <param name="executionSettings">Prompt execution settings</param>
|
||||
/// <param name="kernel">Kernel instance</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
internal async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
this.ValidateChatHistory(chatHistory);
|
||||
|
||||
@@ -264,7 +281,14 @@ internal sealed class MistralClient
|
||||
}
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, [EnumeratorCancellation] CancellationToken cancellationToken, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null)
|
||||
/// <summary>
|
||||
/// Generate new streaming chat message responses.
|
||||
/// </summary>
|
||||
/// <param name="chatHistory">Chat history</param>
|
||||
/// <param name="executionSettings">Prompt execution settings</param>
|
||||
/// <param name="kernel">Kernel instance</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
internal async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
this.ValidateChatHistory(chatHistory);
|
||||
|
||||
@@ -498,66 +522,14 @@ internal sealed class MistralClient
|
||||
}
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<StreamingChatMessageContent> StreamChatMessageContentsAsync(ChatHistory chatHistory, MistralAIPromptExecutionSettings executionSettings, ChatCompletionRequest chatRequest, string modelId, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
this.ValidateChatHistory(chatHistory);
|
||||
|
||||
var endpoint = this.GetEndpoint(executionSettings, path: "chat/completions");
|
||||
using var httpRequestMessage = this.CreatePost(chatRequest, endpoint, this._apiKey, stream: true);
|
||||
using var response = await this.SendStreamingRequestAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false);
|
||||
using var responseStream = await response.Content.ReadAsStreamAndTranslateExceptionAsync().ConfigureAwait(false);
|
||||
await foreach (var streamingChatContent in this.ProcessChatResponseStreamAsync(responseStream, modelId, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
yield return streamingChatContent;
|
||||
}
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<StreamingChatMessageContent> ProcessChatResponseStreamAsync(Stream stream, string modelId, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
IAsyncEnumerator<MistralChatCompletionChunk>? responseEnumerator = null;
|
||||
|
||||
try
|
||||
{
|
||||
var responseEnumerable = this.ParseChatResponseStreamAsync(stream, cancellationToken);
|
||||
responseEnumerator = responseEnumerable.GetAsyncEnumerator(cancellationToken);
|
||||
|
||||
string? currentRole = null;
|
||||
while (await responseEnumerator.MoveNextAsync().ConfigureAwait(false))
|
||||
{
|
||||
var chunk = responseEnumerator.Current!;
|
||||
|
||||
for (int i = 0; i < chunk.GetChoiceCount(); i++)
|
||||
{
|
||||
currentRole ??= chunk.GetRole(i);
|
||||
|
||||
yield return new(role: new AuthorRole(currentRole ?? "assistant"),
|
||||
content: chunk.GetContent(i),
|
||||
choiceIndex: i,
|
||||
modelId: modelId,
|
||||
encoding: chunk.GetEncoding(),
|
||||
innerContent: chunk,
|
||||
metadata: chunk.GetMetadata());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (responseEnumerator != null)
|
||||
{
|
||||
await responseEnumerator.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<MistralChatCompletionChunk> ParseChatResponseStreamAsync(Stream responseStream, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
await foreach (var json in this._streamJsonParser.ParseAsync(responseStream, cancellationToken: cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
yield return DeserializeResponse<MistralChatCompletionChunk>(json);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, CancellationToken cancellationToken, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null)
|
||||
/// <summary>
|
||||
/// Generate embeddings for the provided data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data to create embeddings for</param>
|
||||
/// <param name="executionSettings">Prompt execution settings</param>
|
||||
/// <param name="kernel">Kernel instance</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
internal async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new TextEmbeddingRequest(this._modelId, data);
|
||||
var mistralExecutionSettings = MistralAIPromptExecutionSettings.FromExecutionSettings(executionSettings);
|
||||
@@ -569,6 +541,76 @@ internal sealed class MistralClient
|
||||
return response.Data!.Select(item => new ReadOnlyMemory<float>([.. item.Embedding])).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert <see cref="ChatMessageContent"/> to <see cref="MistralChatMessage"/>
|
||||
/// </summary>
|
||||
/// <param name="content">Chat message content</param>
|
||||
/// <param name="toolCallBehavior">Tool call behavior</param>
|
||||
internal List<MistralChatMessage> ToMistralChatMessages(ChatMessageContent content, MistralAIToolCallBehavior? toolCallBehavior = null)
|
||||
{
|
||||
if (content.Role == AuthorRole.Assistant)
|
||||
{
|
||||
// Handling function calls supplied via ChatMessageContent.Items collection elements of the FunctionCallContent type.
|
||||
var message = new MistralChatMessage(content.Role.ToString(), content.Content ?? string.Empty);
|
||||
Dictionary<string, MistralToolCall> toolCalls = [];
|
||||
foreach (var item in content.Items)
|
||||
{
|
||||
if (item is not FunctionCallContent callRequest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (callRequest.Id is null || toolCalls.ContainsKey(callRequest.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var arguments = JsonSerializer.Serialize(callRequest.Arguments);
|
||||
var toolCall = new MistralToolCall()
|
||||
{
|
||||
Id = callRequest.Id,
|
||||
Function = new MistralFunction(
|
||||
callRequest.FunctionName,
|
||||
callRequest.PluginName)
|
||||
{
|
||||
Arguments = arguments
|
||||
}
|
||||
};
|
||||
toolCalls.Add(callRequest.Id, toolCall);
|
||||
}
|
||||
if (toolCalls.Count > 0)
|
||||
{
|
||||
message.ToolCalls = [.. toolCalls.Values];
|
||||
}
|
||||
return [message];
|
||||
}
|
||||
|
||||
if (content.Role == AuthorRole.Tool)
|
||||
{
|
||||
List<MistralChatMessage>? messages = null;
|
||||
foreach (var item in content.Items)
|
||||
{
|
||||
if (item is not FunctionResultContent resultContent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
messages ??= [];
|
||||
|
||||
var stringResult = ProcessFunctionResult(resultContent.Result ?? string.Empty, toolCallBehavior);
|
||||
messages.Add(new MistralChatMessage(content.Role.ToString(), stringResult));
|
||||
}
|
||||
if (messages is not null)
|
||||
{
|
||||
return messages;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("No function result provided in the tool message.");
|
||||
}
|
||||
|
||||
return [new MistralChatMessage(content.Role.ToString(), content.Content ?? string.Empty)];
|
||||
}
|
||||
|
||||
#region private
|
||||
private readonly string _modelId;
|
||||
private readonly string _apiKey;
|
||||
@@ -576,6 +618,7 @@ internal sealed class MistralClient
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger _logger;
|
||||
private readonly StreamJsonParser _streamJsonParser;
|
||||
private readonly FunctionCallsProcessor _functionCallsProcessor;
|
||||
|
||||
/// <summary>Provider name used for diagnostics.</summary>
|
||||
private const string ModelProvider = "mistralai";
|
||||
@@ -701,69 +744,63 @@ internal sealed class MistralClient
|
||||
return request;
|
||||
}
|
||||
|
||||
internal List<MistralChatMessage> ToMistralChatMessages(ChatMessageContent content, MistralAIToolCallBehavior? toolCallBehavior)
|
||||
private async IAsyncEnumerable<StreamingChatMessageContent> StreamChatMessageContentsAsync(ChatHistory chatHistory, MistralAIPromptExecutionSettings executionSettings, ChatCompletionRequest chatRequest, string modelId, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
if (content.Role == AuthorRole.Assistant)
|
||||
this.ValidateChatHistory(chatHistory);
|
||||
|
||||
var endpoint = this.GetEndpoint(executionSettings, path: "chat/completions");
|
||||
using var httpRequestMessage = this.CreatePost(chatRequest, endpoint, this._apiKey, stream: true);
|
||||
using var response = await this.SendStreamingRequestAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false);
|
||||
using var responseStream = await response.Content.ReadAsStreamAndTranslateExceptionAsync().ConfigureAwait(false);
|
||||
await foreach (var streamingChatContent in this.ProcessChatResponseStreamAsync(responseStream, modelId, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
// Handling function calls supplied via ChatMessageContent.Items collection elements of the FunctionCallContent type.
|
||||
var message = new MistralChatMessage(content.Role.ToString(), content.Content ?? string.Empty);
|
||||
Dictionary<string, MistralToolCall> toolCalls = [];
|
||||
foreach (var item in content.Items)
|
||||
{
|
||||
if (item is not FunctionCallContent callRequest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (callRequest.Id is null || toolCalls.ContainsKey(callRequest.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var arguments = JsonSerializer.Serialize(callRequest.Arguments);
|
||||
var toolCall = new MistralToolCall()
|
||||
{
|
||||
Id = callRequest.Id,
|
||||
Function = new MistralFunction(
|
||||
callRequest.FunctionName,
|
||||
callRequest.PluginName)
|
||||
{
|
||||
Arguments = arguments
|
||||
}
|
||||
};
|
||||
toolCalls.Add(callRequest.Id, toolCall);
|
||||
}
|
||||
if (toolCalls.Count > 0)
|
||||
{
|
||||
message.ToolCalls = [.. toolCalls.Values];
|
||||
}
|
||||
return [message];
|
||||
yield return streamingChatContent;
|
||||
}
|
||||
}
|
||||
|
||||
if (content.Role == AuthorRole.Tool)
|
||||
private async IAsyncEnumerable<StreamingChatMessageContent> ProcessChatResponseStreamAsync(Stream stream, string modelId, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
IAsyncEnumerator<MistralChatCompletionChunk>? responseEnumerator = null;
|
||||
|
||||
try
|
||||
{
|
||||
List<MistralChatMessage>? messages = null;
|
||||
foreach (var item in content.Items)
|
||||
var responseEnumerable = this.ParseChatResponseStreamAsync(stream, cancellationToken);
|
||||
responseEnumerator = responseEnumerable.GetAsyncEnumerator(cancellationToken);
|
||||
|
||||
string? currentRole = null;
|
||||
while (await responseEnumerator.MoveNextAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (item is not FunctionResultContent resultContent)
|
||||
var chunk = responseEnumerator.Current!;
|
||||
|
||||
for (int i = 0; i < chunk.GetChoiceCount(); i++)
|
||||
{
|
||||
continue;
|
||||
currentRole ??= chunk.GetRole(i);
|
||||
|
||||
yield return new(role: new AuthorRole(currentRole ?? "assistant"),
|
||||
content: chunk.GetContent(i),
|
||||
choiceIndex: i,
|
||||
modelId: modelId,
|
||||
encoding: chunk.GetEncoding(),
|
||||
innerContent: chunk,
|
||||
metadata: chunk.GetMetadata());
|
||||
}
|
||||
|
||||
messages ??= [];
|
||||
|
||||
var stringResult = ProcessFunctionResult(resultContent.Result ?? string.Empty, toolCallBehavior);
|
||||
messages.Add(new MistralChatMessage(content.Role.ToString(), stringResult));
|
||||
}
|
||||
if (messages is not null)
|
||||
{
|
||||
return messages;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("No function result provided in the tool message.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (responseEnumerator != null)
|
||||
{
|
||||
await responseEnumerator.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [new MistralChatMessage(content.Role.ToString(), content.Content ?? string.Empty)];
|
||||
private async IAsyncEnumerable<MistralChatCompletionChunk> ParseChatResponseStreamAsync(Stream responseStream, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
await foreach (var json in this._streamJsonParser.ParseAsync(responseStream, cancellationToken: cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
yield return DeserializeResponse<MistralChatCompletionChunk>(json);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpRequestMessage CreatePost(object requestData, Uri endpoint, string apiKey, bool stream)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<!-- IMPORT NUGET PACKAGE SHARED PROPERTIES -->
|
||||
<Import Project="$(RepoRoot)/dotnet/nuget/nuget-package.props" />
|
||||
<Import Project="$(RepoRoot)/dotnet/src/InternalUtilities/src/InternalUtilities.props" />
|
||||
<Import Project="$(RepoRoot)/dotnet/src/InternalUtilities/connectors/AI/FunctionCalling/FunctionCallingUtilities.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- NuGet Package Settings -->
|
||||
|
||||
+2
-2
@@ -45,11 +45,11 @@ public sealed class MistralAIChatCompletionService : IChatCompletionService
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
=> this.Client.GetChatMessageContentsAsync(chatHistory, cancellationToken, executionSettings, kernel);
|
||||
=> this.Client.GetChatMessageContentsAsync(chatHistory, executionSettings, kernel, cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
=> this.Client.GetStreamingChatMessageContentsAsync(chatHistory, cancellationToken, executionSettings, kernel);
|
||||
=> this.Client.GetStreamingChatMessageContentsAsync(chatHistory, executionSettings, kernel, cancellationToken);
|
||||
|
||||
#region private
|
||||
private Dictionary<string, object?> AttributesInternal { get; } = new();
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ public sealed class MistralAITextEmbeddingGenerationService : ITextEmbeddingGene
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
=> this.Client.GenerateEmbeddingsAsync(data, cancellationToken, executionSettings: null, kernel);
|
||||
=> this.Client.GenerateEmbeddingsAsync(data, executionSettings: null, kernel, cancellationToken);
|
||||
|
||||
#region private
|
||||
private Dictionary<string, object?> AttributesInternal { get; } = [];
|
||||
|
||||
Reference in New Issue
Block a user