Cancel "zombie" thread runs Occasionally, thread runs remain in an "in_progress" state even after delivering the response. These "zombie" runs obstruct the addition of new messages to the thread and must be manually cancelled once the run step has been retrieved. Change-Id: I967da84bba66ed8b489b5fdc79001b62b8a9ec5d Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/UriResourceLocatorStateful.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/UriResourceLocatorStateful.java index a313d5a..b56aa43 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/UriResourceLocatorStateful.java +++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/UriResourceLocatorStateful.java
@@ -36,4 +36,8 @@ public static String runStepsUri(String threadId, String runId) { return runRetrieveUri(threadId, runId) + "/steps"; } + + public static String runCancelUri(String threadId, String runId) { + return runRetrieveUri(threadId, runId) + "/cancel"; + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptClientStateful.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptClientStateful.java index ca3bc3d..f0eb5f8 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptClientStateful.java +++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptClientStateful.java
@@ -67,13 +67,16 @@ requestBody = chatGptThreadMessage.getAddMessageRequestBody(); log.debug("ChatGPT request body: {}", requestBody); - return getResponseContentStateful(threadId, chatGptRun); + ChatGptResponseContent chatGptResponseContent = getResponseContentStateful(threadId, chatGptRun); + chatGptRun.cancelRun(); + + return chatGptResponseContent; } private ChatGptResponseContent getResponseContentStateful(String threadId, ChatGptRun chatGptRun) { return switch (chatGptRun.getFirstStepDetails().getType()) { case TYPE_MESSAGE_CREATION -> retrieveThreadMessage(threadId, chatGptRun); - case TYPE_TOOL_CALLS -> getResponseContent(chatGptRun.getFirstStep()); + case TYPE_TOOL_CALLS -> getResponseContent(chatGptRun.getFirstStepToolCalls()); default -> throw new IllegalStateException("Unexpected Step Type in stateful ChatGpt response: " + chatGptRun); };
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptRun.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptRun.java index 31d537e..1fa4b0d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptRun.java +++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/api/chatgpt/ChatGptRun.java
@@ -28,6 +28,7 @@ "cancelling" )); public static final String COMPLETED_STATUS = "completed"; + public static final String CANCELLED_STATUS = "cancelled"; private final ChatGptHttpClient httpClient = new ChatGptHttpClient(); private final ChangeSetData changeSetData; @@ -100,13 +101,35 @@ } public ChatGptResponseMessage getFirstStepDetails() { - return stepResponse.getData().get(0).getStepDetails(); + return getFirstStep().getStepDetails(); } - public List<ChatGptToolCall> getFirstStep() { + public List<ChatGptToolCall> getFirstStepToolCalls() { return getFirstStepDetails().getToolCalls(); } + public void cancelRun() { + if (getFirstStep().getStatus().equals(COMPLETED_STATUS)) return; + + Request cancelRequest = getCancelRequest(); + log.debug("ChatGPT Cancel Run request: {}", cancelRequest); + try { + String fullResponse = httpClient.execute(cancelRequest); + log.debug("ChatGPT Cancel Run Full response: {}", fullResponse); + ChatGptResponse response = getGson().fromJson(fullResponse, ChatGptResponse.class); + if (!response.getStatus().equals(CANCELLED_STATUS)) { + log.error("Unable to cancel run. Run cancel response: {}", fullResponse); + } + } + catch (Exception e) { + log.error("Error cancelling run", e); + } + } + + private ChatGptRunStepsResponse getFirstStep() { + return stepResponse.getData().get(0); + } + private Request runCreateRequest() { URI uri = URI.create(config.getGptDomain() + UriResourceLocatorStateful.runsUri(threadId)); log.debug("ChatGPT Create Run request URI: {}", uri); @@ -135,6 +158,14 @@ return getRunPollRequest(uri); } + private Request getCancelRequest() { + URI uri = URI.create(config.getGptDomain() + + UriResourceLocatorStateful.runCancelUri(threadId, runResponse.getId())); + log.debug("ChatGPT Run Cancel request URI: {}", uri); + + return httpClient.createRequestFromJson(uri.toString(), config.getGptToken(), new Object()); + } + private Request getRunPollRequest(URI uri) { return httpClient.createRequestFromJson(uri.toString(), config.getGptToken(), null); }
diff --git a/src/test/resources/__files/chatGptResponseRequestMessageStateful.json b/src/test/resources/__files/chatGptResponseRequestMessageStateful.json index 812caa4..37709e9 100644 --- a/src/test/resources/__files/chatGptResponseRequestMessageStateful.json +++ b/src/test/resources/__files/chatGptResponseRequestMessageStateful.json
@@ -4,6 +4,7 @@ { "id": "step_UKMPnSinQy6XjSWO7SFleu1v", "object": "thread.run.step", + "status": "completed", "step_details": { "type": "message_creation", "message_creation": {
diff --git a/src/test/resources/__files/chatGptResponseRequestStateful.json b/src/test/resources/__files/chatGptResponseRequestStateful.json index b66217b..a3c26e4 100644 --- a/src/test/resources/__files/chatGptResponseRequestStateful.json +++ b/src/test/resources/__files/chatGptResponseRequestStateful.json
@@ -4,6 +4,7 @@ { "id": "step_UKMPny6XSinQjSWOhSFleu1v", "object": "thread.run.step", + "status": "completed", "step_details": { "type": "tool_calls", "tool_calls": [
diff --git a/src/test/resources/__files/chatGptRunStepsResponse.json b/src/test/resources/__files/chatGptRunStepsResponse.json index b9b6044..3b92beb 100644 --- a/src/test/resources/__files/chatGptRunStepsResponse.json +++ b/src/test/resources/__files/chatGptRunStepsResponse.json
@@ -4,6 +4,7 @@ { "id": "step_TEST_STEP_ID", "object": "thread.run.step", + "status": "completed", "created_at": 1714983398.0, "run_id": "run_TEST_RUN_ID", "assistant_id": "asst_TEST_ASSISTANT_ID",