Skip to content

Commit a70c6c5

Browse files
claudiamurialdoBeta Bot
authored andcommitted
Cherry pick branch 'genexuslabs:embedding-data-type' into beta
1 parent 3da2ff8 commit a70c6c5

6 files changed

Lines changed: 186 additions & 93 deletions

File tree

dotnet/src/dotnetcore/GxClasses/GxClasses.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<Compile Include="..\..\dotnetframework\GxClasses\Diagnostics\GXDebugManager.cs" Link="Diagnostics\GXDebugManager.cs" />
4141
<Compile Include="..\..\dotnetframework\GxClasses\Domain\CallResult.cs" Link="Domain\CallResult.cs" />
4242
<Compile Include="..\..\dotnetframework\GxClasses\Domain\ChatMessage.cs" Link="Domain\ChatMessage.cs" />
43+
<Compile Include="..\..\dotnetframework\GxClasses\Domain\ChatResult.cs" Link="Domain\ChatResult.cs" />
4344
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GXLDAP.cs" Link="Domain\GXLDAP.cs" />
4445
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GxMessages.cs" Link="Domain\GxMessages.cs" />
4546
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GxMessaging.cs" Link="Domain\GxMessaging.cs" />

dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,31 @@ namespace GeneXus.AI
1111
public class GXAgent : GXProcedure
1212
{
1313
static readonly IGXLogger log = GXLoggerFactory.GetLogger<GXAgent>();
14-
const string FINISH_REASON_STOP = "stop";
15-
const string FINISH_REASON_TOOL_CALLS = "tool_calls";
1614
protected string CallAssistant(string assistant, GXProperties properties, object result)
1715
{
18-
return CallAgent(assistant, properties, null, result);
16+
return CallAgent(assistant, properties, null, result, false);
1917
}
20-
protected string CallAgent(string assistant, GXProperties gxproperties, IList chatMessages, object result)
18+
protected string CallAgent(string assistant, GXProperties gxproperties, IList chatMessages, object result, bool stream)
2119
{
2220
CallResult callResult = result as CallResult;
2321
try
2422
{
2523
GXLogging.Debug(log, "Calling Agent: ", assistant);
2624

2725
List<ChatMessage> chatMessagesList = chatMessages!=null ? chatMessages.Cast<ChatMessage>().ToList() :null;
28-
ChatCompletionResult chatCompletion = AgentService.AgentHandlerInstance.Assistant(assistant, chatMessagesList, gxproperties).GetAwaiter().GetResult();
26+
ChatCompletionResult chatCompletion = AgentService.AgentHandlerInstance.Assistant(assistant, chatMessagesList, gxproperties, stream).GetAwaiter().GetResult();
2927

3028
if (chatCompletion != null && chatCompletion.Choices != null)
3129
{
3230
foreach (Choice choice in chatCompletion.Choices)
3331
{
3432
switch (choice.FinishReason.ToLower())
3533
{
36-
case FINISH_REASON_STOP:
34+
case ChatCompletionResult.FINISH_REASON_STOP:
3735
return choice.Message.Content;
38-
case FINISH_REASON_TOOL_CALLS:
36+
case ChatCompletionResult.FINISH_REASON_TOOL_CALLS:
3937
chatMessagesList.Add(choice.Message);
40-
foreach (ToolCall toolCall in choice.Message.ToolCalls)
41-
ProcessTollCall(toolCall, chatMessagesList);
42-
return CallAgent(assistant, gxproperties, chatMessagesList, result);
38+
return ProcessChatResponse(choice, stream, assistant, gxproperties, chatMessagesList, result);
4339
}
4440
}
4541
}
@@ -53,7 +49,13 @@ protected string CallAgent(string assistant, GXProperties gxproperties, IList ch
5349
}
5450

5551
}
56-
private void ProcessTollCall(ToolCall toolCall, List<ChatMessage> messages)
52+
internal override string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, List<ChatMessage> chatMessagesList, object result)
53+
{
54+
foreach (ToolCall toolCall in choice.Message.ToolCalls)
55+
ProcessToolCall(toolCall, chatMessagesList);
56+
return CallAgent(assistant, gxproperties, chatMessagesList, result, stream);
57+
}
58+
private void ProcessToolCall(ToolCall toolCall, List<ChatMessage> messages)
5759
{
5860
string result = string.Empty;
5961
string functionName = toolCall.Function.Name;
@@ -66,10 +68,12 @@ private void ProcessTollCall(ToolCall toolCall, List<ChatMessage> messages)
6668
GXLogging.Error(log, "Error calling tool ", functionName, ex);
6769
result = $"Error calling tool {functionName}";
6870
}
69-
ChatMessage toolCallMessage = new ChatMessage();
70-
toolCallMessage.Role = "tool";
71-
toolCallMessage.Content = result;
72-
toolCallMessage.ToolCallId = toolCall.Id;
71+
ChatMessage toolCallMessage = new ChatMessage
72+
{
73+
Role = "tool",
74+
Content = result,
75+
ToolCallId = toolCall.Id
76+
};
7377
messages.Add(toolCallMessage);
7478
}
7579
protected virtual string CallTool(string name, string arguments)

dotnet/src/dotnetcore/Providers/AI/Services/AgentService.cs

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ static string AddChatToUrl(string url)
6161
uriBuilder.Path += "chat";
6262
return uriBuilder.Uri.ToString();
6363
}
64-
internal async Task<ChatCompletionResult> Assistant(string assistant, List<Chat.ChatMessage> messages, GXProperties properties)
64+
internal async Task<ChatCompletionResult> Assistant(string assistant, List<Chat.ChatMessage> messages, GXProperties properties, bool stream)
6565
{
6666
try
6767
{
6868
ChatRequestPayload requestBody = new ChatRequestPayload();
6969
requestBody.Model = $"{SAIA_AGENT}{assistant}";
7070
requestBody.Messages = messages;
7171
requestBody.Variables = properties.ToList();
72-
requestBody.Stream = false;
72+
requestBody.Stream = stream;
7373

7474
JsonSerializerOptions options = new JsonSerializerOptions
7575
{
@@ -134,79 +134,4 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
134134
}
135135
}
136136

137-
internal class ChatRequestPayload
138-
{
139-
[JsonPropertyName("model")]
140-
public string Model { get; set; }
141-
142-
[JsonPropertyName("messages")]
143-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
144-
public List<Chat.ChatMessage> Messages { get; set; }
145-
146-
[JsonPropertyName("stream")]
147-
public bool? Stream { get; set; }
148-
149-
[JsonPropertyName("variables")]
150-
public List<GxKeyValuePair> Variables { get; set; }
151-
}
152-
153-
internal class ChatCompletionResult
154-
{
155-
[JsonPropertyName("id")]
156-
public string Id { get; set; }
157-
158-
[JsonPropertyName("object")]
159-
public string Object { get; set; }
160-
161-
[JsonPropertyName("created")]
162-
public long Created { get; set; }
163-
164-
[JsonPropertyName("choices")]
165-
public List<Choice> Choices { get; set; }
166-
167-
[JsonPropertyName("usage")]
168-
public Usage Usage { get; set; }
169-
170-
[JsonPropertyName("tool_calls")]
171-
public List<ChatMessage> ToolCalls { get; set; }
172-
173-
[JsonPropertyName("data")]
174-
public List<DataItem> Data { get; set; }
175-
}
176-
public class Choice
177-
{
178-
[JsonPropertyName("index")]
179-
public int Index { get; set; }
180-
181-
[JsonPropertyName("message")]
182-
public ChatMessage Message { get; set; }
183-
184-
[JsonPropertyName("finish_reason")]
185-
public string FinishReason { get; set; }
186-
}
187-
188-
189-
public class Usage
190-
{
191-
[JsonPropertyName("prompt_tokens")]
192-
public int PromptTokens { get; set; }
193-
194-
[JsonPropertyName("completion_tokens")]
195-
public int CompletionTokens { get; set; }
196-
197-
[JsonPropertyName("total_tokens")]
198-
public int TotalTokens { get; set; }
199-
}
200-
201-
public class DataItem
202-
{
203-
[JsonPropertyName("id")]
204-
public string Id { get; set; }
205-
206-
[JsonPropertyName("object")]
207-
public string Object { get; set; }
208-
209-
[JsonPropertyName("embedding")]
210-
public List<double> Embedding { get; set; }
211-
}
212137
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
5+
using GeneXus.Http.Client;
6+
using GeneXus.Procedure;
7+
using GeneXus.Utils;
8+
9+
namespace GeneXus.AI.Chat
10+
{
11+
public class ChatResult
12+
{
13+
#if NETCORE
14+
static readonly IGXLogger log = GXLoggerFactory.GetLogger<ChatResult>();
15+
#endif
16+
17+
private GxHttpClient Client { get; set; }
18+
private string Agent { get; set; }
19+
private GXProperties Properties { get; set; }
20+
private List<ChatMessage> Messages { get; set; }
21+
private CallResult Result { get; set; }
22+
private GXProcedure AgentProcedure { get; set; }
23+
24+
public ChatResult()
25+
{
26+
}
27+
28+
public ChatResult(GXProcedure agentProcedure, string agent, GXProperties properties, List<ChatMessage> messages, CallResult result, GxHttpClient client)
29+
{
30+
AgentProcedure = agentProcedure;
31+
Agent = agent;
32+
Properties = properties;
33+
Messages = messages;
34+
Result = result;
35+
Client = client;
36+
}
37+
public bool HasMoreData()
38+
{
39+
return !Client.Eof;
40+
}
41+
public string GetMoreData()
42+
{
43+
#if NETCORE
44+
string data = Client.ReadChunk();
45+
if (string.IsNullOrEmpty(data))
46+
return string.Empty;
47+
int index = data.IndexOf(ChatCompletionResult.DATA) + ChatCompletionResult.DATA.Length;
48+
string chunkJson = data.Substring(index).Trim();
49+
try
50+
{
51+
ChatCompletionResult chatCompletion = JsonSerializer.Deserialize<ChatCompletionResult>(chunkJson);
52+
if (chatCompletion?.Choices != null && chatCompletion.Choices.Count > 0)
53+
{
54+
Choice choice = chatCompletion.Choices[0];
55+
if (choice.FinishReason.ToLower() == ChatCompletionResult.FINISH_REASON_TOOL_CALLS && Agent != null)
56+
{
57+
Messages.Add(choice.Message);
58+
return AgentProcedure.ProcessChatResponse(choice, true, Agent, Properties, Messages, Result);
59+
}
60+
else
61+
{
62+
return choice.Message.Content ?? string.Empty;
63+
}
64+
}
65+
}
66+
catch (Exception ex)
67+
{
68+
GXLogging.Error(log, "Error processing chat response:", data, ex);
69+
}
70+
#endif
71+
return string.Empty;
72+
}
73+
}
74+
#if NETCORE
75+
internal class ChatRequestPayload
76+
{
77+
[JsonPropertyName("model")]
78+
public string Model { get; set; }
79+
80+
[JsonPropertyName("messages")]
81+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
82+
public List<Chat.ChatMessage> Messages { get; set; }
83+
84+
[JsonPropertyName("stream")]
85+
public bool? Stream { get; set; }
86+
87+
[JsonPropertyName("variables")]
88+
public List<GxKeyValuePair> Variables { get; set; }
89+
}
90+
91+
internal class ChatCompletionResult
92+
{
93+
internal const string FINISH_REASON_STOP = "stop";
94+
internal const string FINISH_REASON_TOOL_CALLS = "tool_calls";
95+
internal const string DATA = "data:";
96+
97+
[JsonPropertyName("id")]
98+
public string Id { get; set; }
99+
100+
[JsonPropertyName("object")]
101+
public string Object { get; set; }
102+
103+
[JsonPropertyName("created")]
104+
public long Created { get; set; }
105+
106+
[JsonPropertyName("choices")]
107+
public List<Choice> Choices { get; set; }
108+
109+
[JsonPropertyName("usage")]
110+
public Usage Usage { get; set; }
111+
112+
[JsonPropertyName("tool_calls")]
113+
public List<ChatMessage> ToolCalls { get; set; }
114+
115+
[JsonPropertyName("data")]
116+
public List<DataItem> Data { get; set; }
117+
}
118+
#endif
119+
public class Choice
120+
{
121+
[JsonPropertyName("index")]
122+
public int Index { get; set; }
123+
124+
[JsonPropertyName("message")]
125+
public ChatMessage Message { get; set; }
126+
127+
[JsonPropertyName("finish_reason")]
128+
public string FinishReason { get; set; }
129+
}
130+
131+
132+
public class Usage
133+
{
134+
[JsonPropertyName("prompt_tokens")]
135+
public int PromptTokens { get; set; }
136+
137+
[JsonPropertyName("completion_tokens")]
138+
public int CompletionTokens { get; set; }
139+
140+
[JsonPropertyName("total_tokens")]
141+
public int TotalTokens { get; set; }
142+
}
143+
144+
public class DataItem
145+
{
146+
[JsonPropertyName("id")]
147+
public string Id { get; set; }
148+
149+
[JsonPropertyName("object")]
150+
public string Object { get; set; }
151+
152+
[JsonPropertyName("embedding")]
153+
public List<double> Embedding { get; set; }
154+
}
155+
156+
}

dotnet/src/dotnetframework/GxClasses/Model/gxproc.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace GeneXus.Procedure
66
using System.Collections.Generic;
77
using System.IO;
88
using System.Reflection;
9+
using GeneXus.AI.Chat;
910
using GeneXus.Application;
1011
using GeneXus.Configuration;
1112
using GeneXus.Data;
@@ -52,6 +53,11 @@ public GXProcedure()
5253
}
5354
#endif
5455
}
56+
internal virtual string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, List<ChatMessage> chatMessagesList, object result)
57+
{
58+
return string.Empty;
59+
}
60+
5561
protected int MainImplEx(string[] args)
5662
{
5763
try

dotnet/test/DotNetCoreUnitTest/Domain/GxEmbeddingTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Threading.Tasks;
33
using GeneXus.AI;
4+
using GeneXus.AI.Chat;
45
using GeneXus.Utils;
56
using Xunit;
67

@@ -24,7 +25,7 @@ public async Task AssistantTest()
2425
GXProperties properties = new GXProperties();
2526
properties.Set("$context", "context for reference");
2627

27-
ChatCompletionResult embedding = await agentService.Assistant(modelId, null, properties);
28+
ChatCompletionResult embedding = await agentService.Assistant(modelId, null, properties, false);
2829
Assert.NotNull(embedding);
2930
}
3031
}

0 commit comments

Comments
 (0)