From 310f2c14970fc2518ca93a88ad2cfad0ea4e725e Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 16 Nov 2025 00:34:31 +0800 Subject: [PATCH] :bug: Fix function call in chat history issue --- ...2347_UpdatedFunctionCallModels.Designer.cs | 142 ++++++++++++++++++ ...0251115162347_UpdatedFunctionCallModels.cs | 22 +++ .../Thought/ThoughtController.cs | 39 ++++- .../Models/ThinkingSequence.cs | 3 + 4 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.Designer.cs create mode 100644 DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.cs diff --git a/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.Designer.cs b/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.Designer.cs new file mode 100644 index 0000000..6ffc4ec --- /dev/null +++ b/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.Designer.cs @@ -0,0 +1,142 @@ +// +using System; +using System.Collections.Generic; +using DysonNetwork.Insight; +using DysonNetwork.Shared.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DysonNetwork.Insight.Migrations +{ + [DbContext(typeof(AppDatabase))] + [Migration("20251115162347_UpdatedFunctionCallModels")] + partial class UpdatedFunctionCallModels + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PaidToken") + .HasColumnType("bigint") + .HasColumnName("paid_token"); + + b.Property("Topic") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("topic"); + + b.Property("TotalToken") + .HasColumnType("bigint") + .HasColumnName("total_token"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_thinking_sequences"); + + b.ToTable("thinking_sequences", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingThought", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property>("Files") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("files"); + + b.Property("ModelName") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("model_name"); + + b.Property>("Parts") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("parts"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("SequenceId") + .HasColumnType("uuid") + .HasColumnName("sequence_id"); + + b.Property("TokenCount") + .HasColumnType("bigint") + .HasColumnName("token_count"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_thinking_thoughts"); + + b.HasIndex("SequenceId") + .HasDatabaseName("ix_thinking_thoughts_sequence_id"); + + b.ToTable("thinking_thoughts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingThought", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnThinkingSequence", "Sequence") + .WithMany() + .HasForeignKey("SequenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_thinking_thoughts_thinking_sequences_sequence_id"); + + b.Navigation("Sequence"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.cs b/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.cs new file mode 100644 index 0000000..a0b8af3 --- /dev/null +++ b/DysonNetwork.Insight/Migrations/20251115162347_UpdatedFunctionCallModels.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DysonNetwork.Insight.Migrations +{ + /// + public partial class UpdatedFunctionCallModels : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/DysonNetwork.Insight/Thought/ThoughtController.cs b/DysonNetwork.Insight/Thought/ThoughtController.cs index 45c99dd..6077014 100644 --- a/DysonNetwork.Insight/Thought/ThoughtController.cs +++ b/DysonNetwork.Insight/Thought/ThoughtController.cs @@ -112,12 +112,12 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) // Add previous thoughts (excluding the current user thought, which is the first one since descending) var previousThoughts = await service.GetPreviousThoughtsAsync(sequence); var count = previousThoughts.Count; - for (var i = 1; i < count; i++) // skip first (the newest, current user) + for (var i = count - 1; i >= 1; i--) // skip first (the newest, current user) { var thought = previousThoughts[i]; var textContent = new StringBuilder(); var functionCalls = new List(); - var hasFunctionCalls = false; + var functionResults = new List(); foreach (var part in thought.Parts) { @@ -127,15 +127,27 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) textContent.Append(part.Text); break; case ThinkingMessagePartType.FunctionCall: - hasFunctionCalls = true; - functionCalls.Add(new FunctionCallContent(part.FunctionCall!.Name, part.FunctionCall.Arguments, - part.FunctionCall.Id)); + var arguments = !string.IsNullOrEmpty(part.FunctionCall!.Arguments) + ? JsonSerializer.Deserialize>(part.FunctionCall!.Arguments) + : null; + var kernelArgs = arguments is not null ? new KernelArguments(arguments) : null; + + functionCalls.Add(new FunctionCallContent( + functionName: part.FunctionCall!.Name, + pluginName: part.FunctionCall.PluginName, + id: part.FunctionCall.Id, + arguments: kernelArgs + )); break; case ThinkingMessagePartType.FunctionResult: var resultObject = part.FunctionResult!.Result; var resultString = resultObject is string s ? s : JsonSerializer.Serialize(resultObject); - var result = new FunctionResultContent(part.FunctionResult!.CallId, resultString); - chatHistory.Add(result.ToChatMessage()); + functionResults.Add(new FunctionResultContent( + callId: part.FunctionResult.CallId, + functionName: part.FunctionResult.FunctionName, + pluginName: part.FunctionResult.PluginName, + result: resultString + )); break; default: throw new ArgumentOutOfRangeException(); @@ -149,7 +161,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) else { var assistantMessage = new ChatMessageContent(AuthorRole.Assistant, textContent.ToString()); - if (hasFunctionCalls) + if (functionCalls.Count > 0) { assistantMessage.Items = []; foreach (var fc in functionCalls) @@ -159,6 +171,14 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) } chatHistory.Add(assistantMessage); + + if (functionResults.Count > 0) + { + foreach (var fr in functionResults) + { + chatHistory.Add(fr.ToChatMessage()); + } + } } } @@ -231,6 +251,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) FunctionCall = new SnFunctionCall { Id = functionCall.Id!, + PluginName = functionCall.PluginName, Name = functionCall.FunctionName, Arguments = JsonSerializer.Serialize(functionCall.Arguments) } @@ -259,6 +280,8 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service) FunctionResult = new SnFunctionResult { CallId = resultContent.CallId!, + PluginName = resultContent.PluginName, + FunctionName = resultContent.FunctionName, Result = resultContent.Result!, IsError = resultContent.Result is Exception } diff --git a/DysonNetwork.Shared/Models/ThinkingSequence.cs b/DysonNetwork.Shared/Models/ThinkingSequence.cs index 2969064..85ec9e0 100644 --- a/DysonNetwork.Shared/Models/ThinkingSequence.cs +++ b/DysonNetwork.Shared/Models/ThinkingSequence.cs @@ -39,6 +39,7 @@ public class SnThinkingMessagePart public class SnFunctionCall { public string Id { get; set; } = null!; + public string? PluginName { get; set; } public string Name { get; set; } = null!; public string Arguments { get; set; } = null!; } @@ -46,6 +47,8 @@ public class SnFunctionCall public class SnFunctionResult { public string CallId { get; set; } = null!; + public string? PluginName { get; set; } + public string FunctionName { get; set; } = null!; public object Result { get; set; } = null!; public bool IsError { get; set; } }