From 2b0489accfad2147754a523aa61db49d45d270f1 Mon Sep 17 00:00:00 2001 From: claudiamurialdo Date: Mon, 13 Oct 2025 17:47:04 -0300 Subject: [PATCH] The ChatMessages parameter in Agent.Chat was not accumulating messages across calls because it created a copy using ToList(). The DONE response from the chat agent was not being handled correctly. --- dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs | 12 +++++------- .../dotnetcore/Providers/AI/Services/AgentService.cs | 11 +++++++---- .../dotnetframework/GxClasses/Domain/ChatResult.cs | 9 +++++++-- dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs | 3 ++- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs b/dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs index 913af43f0..a749cfee4 100644 --- a/dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs +++ b/dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs @@ -17,20 +17,18 @@ public class GXAgent : GXProcedure protected ChatResult ChatAgent(String agent, GXProperties properties, IList chatMessages, object result) { CallResult callResult = result as CallResult; - List chatMessagesList = chatMessages != null ? chatMessages.Cast().ToList() : null; try { GXLogging.Debug(log, "Chatting Agent: ", agent); - GxHttpClient httpClient = AgentService.AgentHandlerInstance.ChatAgent(agent, chatMessagesList, properties, context); - - return new ChatResult(this, agent, properties, chatMessagesList, callResult, httpClient); + GxHttpClient httpClient = AgentService.AgentHandlerInstance.ChatAgent(agent, chatMessages, properties, context); + return new ChatResult(this, agent, properties, chatMessages, callResult, httpClient); } catch (Exception ex) { callResult.AddMessage($"Error chatting Agent {agent}:" + ex.Message); callResult.IsFail = true; - return new ChatResult(this, agent, properties, chatMessagesList, callResult, null); + return new ChatResult(this, agent, properties, chatMessages, callResult, null); } } protected string CallAgent(string assistant, GXProperties gxproperties, IList chatMessages, object result) @@ -71,13 +69,13 @@ protected string CallAgent(string assistant, GXProperties gxproperties, IList ch } } - internal override string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, List chatMessagesList, object result) + internal override string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, IList chatMessagesList, object result) { foreach (ToolCall toolCall in choice.Message.ToolCalls) ProcessToolCall(toolCall, chatMessagesList); return CallAgent(assistant, gxproperties, chatMessagesList, result, stream); } - private void ProcessToolCall(ToolCall toolCall, List messages) + private void ProcessToolCall(ToolCall toolCall, IList messages) { string result = string.Empty; string functionName = toolCall.Function.Name; diff --git a/dotnet/src/dotnetcore/Providers/AI/Services/AgentService.cs b/dotnet/src/dotnetcore/Providers/AI/Services/AgentService.cs index 88883262f..2d13ca7b8 100644 --- a/dotnet/src/dotnetcore/Providers/AI/Services/AgentService.cs +++ b/dotnet/src/dotnetcore/Providers/AI/Services/AgentService.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; @@ -75,7 +77,7 @@ internal async Task CallAgent(string assistant, List messages, GXProperties properties, IGxContext context) + internal GxHttpClient ChatAgent(string assistant, IList messages, GXProperties properties, IGxContext context) { try { @@ -97,7 +99,7 @@ internal GxHttpClient ChatAgent(string assistant, List message } } - internal GxHttpClient AgentHttpClient(IGxContext context, string assistant, List messages, GXProperties properties, bool stream) + internal GxHttpClient AgentHttpClient(IGxContext context, string assistant, IList messages, GXProperties properties, bool stream) { GxHttpClient httpClient = new GxHttpClient(context); httpClient.Secure = 1; @@ -112,11 +114,12 @@ internal GxHttpClient AgentHttpClient(IGxContext context, string assistant, List return httpClient; } - private string AgentPaylod(string assistant, List messages, GXProperties properties, bool stream) + private string AgentPaylod(string assistant, IList messages, GXProperties properties, bool stream) { + List chatMessagesList = messages != null ? messages.Cast().ToList() : null; ChatRequestPayload requestBody = new ChatRequestPayload(); requestBody.Model = $"{SAIA_AGENT}{assistant}"; - requestBody.Messages = messages; + requestBody.Messages = chatMessagesList; requestBody.Variables = properties.ToList(); requestBody.Stream = stream; diff --git a/dotnet/src/dotnetframework/GxClasses/Domain/ChatResult.cs b/dotnet/src/dotnetframework/GxClasses/Domain/ChatResult.cs index 97351e3fc..118c0d744 100644 --- a/dotnet/src/dotnetframework/GxClasses/Domain/ChatResult.cs +++ b/dotnet/src/dotnetframework/GxClasses/Domain/ChatResult.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; @@ -17,7 +18,7 @@ public class ChatResult: IDisposable private GxHttpClient Client { get; set; } private string Agent { get; set; } private GXProperties Properties { get; set; } - private List Messages { get; set; } + private IList Messages { get; set; } private CallResult Result { get; set; } private GXProcedure AgentProcedure { get; set; } private bool disposed = false; @@ -25,7 +26,7 @@ public ChatResult() { } - public ChatResult(GXProcedure agentProcedure, string agent, GXProperties properties, List messages, CallResult result, GxHttpClient client) + public ChatResult(GXProcedure agentProcedure, string agent, GXProperties properties, IList messages, CallResult result, GxHttpClient client) { AgentProcedure = agentProcedure; Agent = agent; @@ -46,6 +47,8 @@ public string GetMoreData() return string.Empty; int index = data.IndexOf(ChatCompletionResult.DATA) + ChatCompletionResult.DATA.Length; string chunkJson = data.Substring(index).Trim(); + if (chunkJson.Equals(ChatCompletionResult.DONE)) + return string.Empty; try { ChatCompletionResult chatCompletion = JsonSerializer.Deserialize(chunkJson); @@ -117,6 +120,8 @@ internal class ChatCompletionResult internal const string FINISH_REASON_STOP = "stop"; internal const string FINISH_REASON_TOOL_CALLS = "tool_calls"; internal const string DATA = "data:"; + internal const string DONE = "[DONE]"; + [JsonPropertyName("id")] public string Id { get; set; } diff --git a/dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs b/dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs index 5cee9cb33..19a408dc7 100644 --- a/dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs +++ b/dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs @@ -3,6 +3,7 @@ namespace GeneXus.Procedure { using System; + using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; @@ -53,7 +54,7 @@ public GXProcedure() } #endif } - internal virtual string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, List chatMessagesList, object result) + internal virtual string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, IList chatMessagesList, object result) { return string.Empty; }