Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions java/src/main/java/com/genexus/GXProcedure.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.ArrayList;
import java.util.Date;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.genexus.db.Namespace;
import com.genexus.db.UserInformation;
import com.genexus.diagnostics.GXDebugInfo;
Expand All @@ -18,8 +17,8 @@
import com.genexus.util.*;
import com.genexus.util.saia.OpenAIRequest;
import com.genexus.util.saia.OpenAIResponse;
import com.genexus.util.saia.SaiaEvents;
import com.genexus.util.saia.SaiaService;
import org.json.JSONObject;

public abstract class GXProcedure implements IErrorHandler, ISubmitteable {
public abstract void initialize();
Expand Down Expand Up @@ -286,9 +285,9 @@ protected ChatResult chatAgent(String agent, GXProperties properties, ArrayList<
context.setThreadModelContext(context);
callAgent(agent, true, properties, messages, result, chatResult);
} finally {
chatResult.markDone();
if (history != null)
history.setExternalInstance(messages);
chatResult.markDone();
}
}).start();

Expand Down Expand Up @@ -327,16 +326,18 @@ protected String callAgent(String agent, boolean stream, GXProperties properties

public String processNotChunkedResponse(String agent, boolean stream, GXProperties properties, ArrayList<OpenAIResponse.Message> messages, CallResult result, ChatResult chatResult, ArrayList<OpenAIResponse.ToolCall> toolCalls) {
for (OpenAIResponse.ToolCall tollCall : toolCalls) {
processToolCall(tollCall, messages);
processToolCall(tollCall, messages, chatResult);
}
return callAgent(agent, stream, properties, messages, result, chatResult);
}

private void processToolCall(OpenAIResponse.ToolCall toolCall, ArrayList<OpenAIResponse.Message> messages) {
private void processToolCall(OpenAIResponse.ToolCall toolCall, ArrayList<OpenAIResponse.Message> messages, ChatResult chatResult) {
String result;
String functionName = toolCall.getFunction().getName();
try {
addToolCallChunk(chatResult, toolCall, "saia.metadata.tool.started", "started", null);
result = callTool(functionName, toolCall.getFunction().getArguments());
addToolCallChunk(chatResult, toolCall, "saia.metadata.tool.finished", "finished_successfully", result);
}
catch (Throwable e) {
result = String.format("Error calling tool %s", functionName);
Expand All @@ -347,4 +348,13 @@ private void processToolCall(OpenAIResponse.ToolCall toolCall, ArrayList<OpenAIR
toolCallMessage.setToolCallId(toolCall.getId());
messages.add(toolCallMessage);
}

private void addToolCallChunk(ChatResult chatResult, OpenAIResponse.ToolCall toolCall, String event, String tollStatus, String result) {
if (chatResult != null) {
SaiaEvents saiaToolStarted = new SaiaEvents();
String eventJson = saiaToolStarted.serializeSaiaEvent(toolCall, event, tollStatus, result);
if (eventJson != null)
chatResult.addChunk("data: " + eventJson);
}
}
}
139 changes: 139 additions & 0 deletions java/src/main/java/com/genexus/util/saia/SaiaEvents.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.genexus.util.saia;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.genexus.diagnostics.core.ILogger;
import com.genexus.diagnostics.core.LogManager;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class SaiaEvents {
private static final ILogger logger = LogManager.getLogger(SaiaEvents.class);

@JsonProperty("event")
private String event;

@JsonProperty("data")
private Data data;

public String getEvent() {
return event;
}

public void setEvent(String event) {
this.event = event;
}

public Data getData() {
return data;
}

public void setData(Data data) {
this.data = data;
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Data {

@JsonProperty("toolId")
private String toolId;

@JsonProperty("toolName")
private String toolName;

@JsonProperty("timestamp")
private String timestamp;

@JsonProperty("toolDescription")
private String toolDescription;

@JsonProperty("toolStatus")
private String toolStatus;

@JsonProperty("toolResponse")
private String toolResponse;

@JsonProperty("executionId")
private String executionId;

public String getToolId() {
return toolId;
}

public void setToolId(String toolId) {
this.toolId = toolId;
}

public String getToolName() {
return toolName;
}

public void setToolName(String toolName) {
this.toolName = toolName;
}

public String getTimestamp() {
return timestamp;
}

public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}

public String getToolDescription() {
return toolDescription;
}

public void setToolDescription(String toolDescription) {
this.toolDescription = toolDescription;
}

public String getToolResponse() {
return toolResponse;
}

public void setToolResponse(String toolResponse) {
this.toolResponse = toolResponse;
}

public String getToolStatus() {
return toolStatus;
}

public void setToolStatus(String toolStatus) {
this.toolStatus = toolStatus;
}

public String getExecutionId() {
return executionId;
}

public void setExecutionId(String executionId) {
this.executionId = executionId;
}
}

public String serializeSaiaEvent(OpenAIResponse.ToolCall toolCall, String event, String tollStatus, String result) {
SaiaEvents.Data saiaToolStartedData = new SaiaEvents.Data();
saiaToolStartedData.setToolName(toolCall.getFunction().getName());
saiaToolStartedData.setTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")));
saiaToolStartedData.setToolStatus(tollStatus);
saiaToolStartedData.setToolResponse(result);
saiaToolStartedData.setExecutionId(toolCall.getId());
setEvent(event);
setData(saiaToolStartedData);

try {
ObjectMapper mapper = new ObjectMapper();
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
}
catch (JsonProcessingException e) {
logger.error("Serializing Saia Event", e);
return null;
}
}
}
24 changes: 15 additions & 9 deletions java/src/main/java/com/genexus/util/saia/SaiaService.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,21 @@ private static void getChunkedSaiaResponse(GXProcedure proc, HttpClient client,
chunkJson = saiaChunkResponse.substring(index).trim();
try {
JSONObject jsonResponse = new JSONObject(chunkJson);
OpenAIResponse chunkResponse = new ObjectMapper().readValue(jsonResponse.toString(), OpenAIResponse.class);
if (!chunkResponse.getChoices().isEmpty()) {
OpenAIResponse.Choice choice = chunkResponse.getChoices().get(0);
if (choice.getFinishReason() != null && choice.getFinishReason().equals("tool_calls")) {
messages.add(choice.getMessage());
proc.processNotChunkedResponse(agent, stream, properties, messages, result, chatResult, choice.getMessage().getToolCalls());
;
} else if (choice.getDelta() != null && choice.getDelta().getContent() != null) {
chatResult.addChunk(((OpenAIResponse.StringContent) choice.getDelta().getContent()).getValue());
if (jsonResponse.has("event") && jsonResponse.has("data")) {

chatResult.addChunk(saiaChunkResponse);
}
else {
OpenAIResponse chunkResponse = new ObjectMapper().readValue(jsonResponse.toString(), OpenAIResponse.class);
if (!chunkResponse.getChoices().isEmpty()) {
OpenAIResponse.Choice choice = chunkResponse.getChoices().get(0);
if (choice.getFinishReason() != null && choice.getFinishReason().equals("tool_calls")) {
messages.add(choice.getMessage());
proc.processNotChunkedResponse(agent, stream, properties, messages, result, chatResult, choice.getMessage().getToolCalls());
;
} else if (choice.getDelta() != null && choice.getDelta().getContent() != null) {
chatResult.addChunk(((OpenAIResponse.StringContent) choice.getDelta().getContent()).getValue());
}
}
}
saiaChunkResponse = client.readChunk();
Expand Down
Loading