🐛 Fix function calls in thought

This commit is contained in:
2025-11-15 23:43:22 +08:00
parent c69256bda6
commit 0ae8a2cfd4
2 changed files with 31 additions and 33 deletions

View File

@@ -137,6 +137,8 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
var result = new FunctionResultContent(part.FunctionResult!.CallId, resultString); var result = new FunctionResultContent(part.FunctionResult!.CallId, resultString);
chatHistory.Add(result.ToChatMessage()); chatHistory.Add(result.ToChatMessage());
break; break;
default:
throw new ArgumentOutOfRangeException();
} }
} }
@@ -149,7 +151,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
var assistantMessage = new ChatMessageContent(AuthorRole.Assistant, textContent.ToString()); var assistantMessage = new ChatMessageContent(AuthorRole.Assistant, textContent.ToString());
if (hasFunctionCalls) if (hasFunctionCalls)
{ {
assistantMessage.Items = new ChatMessageContentItemCollection(); assistantMessage.Items = [];
foreach (var fc in functionCalls) foreach (var fc in functionCalls)
{ {
assistantMessage.Items.Add(fc); assistantMessage.Items.Add(fc);
@@ -178,8 +180,10 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
AuthorRole? authorRole = null; AuthorRole? authorRole = null;
var functionCallBuilder = new FunctionCallContentBuilder(); var functionCallBuilder = new FunctionCallContentBuilder();
await foreach (var streamingContent in chatCompletionService.GetStreamingChatMessageContentsAsync( await foreach (
chatHistory, executionSettings, kernel)) var streamingContent in chatCompletionService.GetStreamingChatMessageContentsAsync(
chatHistory, executionSettings, kernel)
)
{ {
authorRole ??= streamingContent.Role; authorRole ??= streamingContent.Role;
@@ -192,18 +196,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
await Response.Body.FlushAsync(); await Response.Body.FlushAsync();
} }
if (streamingContent.Items.Count > 0) functionCallBuilder.Append(streamingContent);
{
functionCallBuilder.Append(streamingContent);
}
foreach (var functionCallUpdate in streamingContent.Items.OfType<StreamingFunctionCallUpdateContent>())
{
var messageJson = JsonSerializer.Serialize(new
{ type = "function_call_update", data = functionCallUpdate });
await Response.Body.WriteAsync(Encoding.UTF8.GetBytes($"data: {messageJson}\n\n"));
await Response.Body.FlushAsync();
}
} }
var finalMessageText = textContentBuilder.ToString(); var finalMessageText = textContentBuilder.ToString();
@@ -213,19 +206,21 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
{ Type = ThinkingMessagePartType.Text, Text = finalMessageText }); { Type = ThinkingMessagePartType.Text, Text = finalMessageText });
} }
var functionCalls = functionCallBuilder.Build(); var functionCalls = functionCallBuilder.Build()
.Where(fc => !string.IsNullOrEmpty(fc.Id)).ToList();
if (functionCalls.Count == 0) if (functionCalls.Count == 0)
{
break; break;
}
var assistantMessage = new ChatMessageContent(authorRole ?? AuthorRole.Assistant, var assistantMessage = new ChatMessageContent(
string.IsNullOrEmpty(finalMessageText) ? null : finalMessageText); authorRole ?? AuthorRole.Assistant,
string.IsNullOrEmpty(finalMessageText) ? null : finalMessageText
);
foreach (var functionCall in functionCalls) foreach (var functionCall in functionCalls)
{ {
assistantMessage.Items.Add(functionCall); assistantMessage.Items.Add(functionCall);
} }
chatHistory.Add(assistantMessage); chatHistory.Add(assistantMessage);
foreach (var functionCall in functionCalls) foreach (var functionCall in functionCalls)
@@ -236,7 +231,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
FunctionCall = new SnFunctionCall FunctionCall = new SnFunctionCall
{ {
Id = functionCall.Id!, Id = functionCall.Id!,
Name = functionCall.FunctionName!, Name = functionCall.FunctionName,
Arguments = JsonSerializer.Serialize(functionCall.Arguments) Arguments = JsonSerializer.Serialize(functionCall.Arguments)
} }
}; };
@@ -263,7 +258,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
Type = ThinkingMessagePartType.FunctionResult, Type = ThinkingMessagePartType.FunctionResult,
FunctionResult = new SnFunctionResult FunctionResult = new SnFunctionResult
{ {
CallId = resultContent.CallId, CallId = resultContent.CallId!,
Result = resultContent.Result!, Result = resultContent.Result!,
IsError = resultContent.Result is Exception IsError = resultContent.Result is Exception
} }

View File

@@ -73,21 +73,24 @@ public class ThoughtProvider
throw new IndexOutOfRangeException("Unknown thinking provider: " + ModelProviderType); throw new IndexOutOfRangeException("Unknown thinking provider: " + ModelProviderType);
} }
// Add gRPC clients for Thought Plugins
builder.Services.AddServiceDiscoveryCore();
builder.Services.AddServiceDiscovery();
builder.Services.AddAccountService();
builder.Services.AddSphereService();
builder.Plugins.AddFromType<SnAccountKernelPlugin>();
builder.Plugins.AddFromType<SnPostKernelPlugin>();
return builder.Build(); return builder.Build();
} }
[Experimental("SKEXP0050")] [Experimental("SKEXP0050")]
private void InitializeHelperFunctions() private void InitializeHelperFunctions()
{ {
var accountPlugin = new SnAccountKernelPlugin(_accountClient);
var postPlugin = new SnPostKernelPlugin(_postClient);
// Add Solar Network tools plugin
Kernel.ImportPluginFromFunctions("solar_network", [
KernelFunctionFactory.CreateFromMethod(accountPlugin.GetAccount),
KernelFunctionFactory.CreateFromMethod(accountPlugin.GetAccountByName),
KernelFunctionFactory.CreateFromMethod(postPlugin.GetPost),
KernelFunctionFactory.CreateFromMethod(postPlugin.ListPosts),
KernelFunctionFactory.CreateFromMethod(postPlugin.ListPostsWithinTime)
]);
// Add web search plugins if configured // Add web search plugins if configured
var bingApiKey = _configuration.GetValue<string>("Thinking:BingApiKey"); var bingApiKey = _configuration.GetValue<string>("Thinking:BingApiKey");
if (!string.IsNullOrEmpty(bingApiKey)) if (!string.IsNullOrEmpty(bingApiKey))
@@ -116,12 +119,12 @@ public class ThoughtProvider
case "ollama": case "ollama":
return new OllamaPromptExecutionSettings return new OllamaPromptExecutionSettings
{ {
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false)
}; };
case "deepseek": case "deepseek":
return new OpenAIPromptExecutionSettings return new OpenAIPromptExecutionSettings
{ {
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false)
}; };
default: default:
throw new InvalidOperationException("Unknown provider: " + ModelProviderType); throw new InvalidOperationException("Unknown provider: " + ModelProviderType);