From 5cf1c2f75d03544cf013a97192f9a0b1572ea3dc Mon Sep 17 00:00:00 2001 From: Florian Magin Date: Thu, 21 May 2026 12:33:09 +0200 Subject: [PATCH] Update SDK for new decomp endpoints --- build.gradle | 2 +- .../aidecompiler/AIDecompilationdWindow.java | 23 +++++++++---------- .../services/api/GhidraRevengService.java | 12 ++++------ .../services/api/TypedApiImplementation.java | 7 +++--- .../ai/reveng/AIDecompilerComponentTest.java | 7 +++--- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/build.gradle b/build.gradle index 68ddccca..7c6e1041 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation 'org.json:json:20250107' implementation "com.google.guava:guava:33.2.0-jre" implementation group: 'com.fifesoft', name: 'rsyntaxtextarea', version: '3.5.2' - implementation('ai.reveng:sdk:3.0.0') + implementation('ai.reveng:sdk:3.82.2') testImplementation('junit:junit:4.13.1') testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.8.2") diff --git a/src/main/java/ai/reveng/toolkit/ghidra/binarysimilarity/ui/aidecompiler/AIDecompilationdWindow.java b/src/main/java/ai/reveng/toolkit/ghidra/binarysimilarity/ui/aidecompiler/AIDecompilationdWindow.java index 1df4868f..f0b14165 100644 --- a/src/main/java/ai/reveng/toolkit/ghidra/binarysimilarity/ui/aidecompiler/AIDecompilationdWindow.java +++ b/src/main/java/ai/reveng/toolkit/ghidra/binarysimilarity/ui/aidecompiler/AIDecompilationdWindow.java @@ -1,6 +1,7 @@ package ai.reveng.toolkit.ghidra.binarysimilarity.ui.aidecompiler; import ai.reveng.invoker.ApiException; +import ai.reveng.model.AiDecompilationTaskStatus; import ai.reveng.model.GetAiDecompilationTask; import ai.reveng.toolkit.ghidra.core.services.api.GhidraRevengService; import ai.reveng.toolkit.ghidra.core.services.api.TypedApiInterface; @@ -207,7 +208,7 @@ public JComponent getComponent() { public void setDisplayedValuesBasedOnStatus(Function function, GetAiDecompilationTask status) { this.function = function; - if (status.getStatus().equals("success")) { + if (status.getStatus() == AiDecompilationTaskStatus.SUCCESS) { setCode(status.getDecompilation()); descriptionArea.setText("%s".formatted(status.getSummary())); @@ -219,7 +220,7 @@ public void setDisplayedValuesBasedOnStatus(Function function, GetAiDecompilatio } else { predictedNamePanel.setVisible(false); } - } else if (status.getStatus().equals("error")) { + } else if (status.getStatus() == AiDecompilationTaskStatus.ERROR) { setCode(""); descriptionArea.setText("Decompilation failed"); predictedNamePanel.setVisible(false); @@ -286,13 +287,13 @@ void newStatusForFunction(Function function, GetAiDecompilationTask status) { setDisplayedValuesBasedOnStatus(function, status) ); } - if (status.getStatus().equals("success")) { + if (status.getStatus() == AiDecompilationTaskStatus.SUCCESS) { var logger = tool.getService(ReaiLoggingService.class); logger.info("AI Decompilation finished for function %s: %s".formatted(function.getName(), status.getDecompilation())); if (!hasPendingDecompilations()) { taskMonitorComponent.setVisible(false); } - } else if (status.getStatus().equals("error")) { + } else if (status.getStatus() == AiDecompilationTaskStatus.ERROR) { if (!hasPendingDecompilations()) { taskMonitorComponent.setVisible(false); } @@ -300,7 +301,7 @@ void newStatusForFunction(Function function, GetAiDecompilationTask status) { } private boolean hasPendingDecompilations() { - return cache.values().stream().anyMatch(s -> s.getStatus().equals("pending") || s.getStatus().equals("running") || s.getStatus().equals("queued")); + return cache.values().stream().anyMatch(s -> s.getStatus() == AiDecompilationTaskStatus.PENDING); } class AIDecompTask extends Task { @@ -317,7 +318,7 @@ public AIDecompTask(PluginTool tool, GhidraRevengService.FunctionWithID function public void run(TaskMonitor monitor) throws CancelledException { var fID = functionWithID.functionID(); // Check if there is an existing process already, because the trigger API will fail with 400 if there is - if (service.getApi().pollAIDecompileStatus(fID).getStatus().equals("uninitialised")) { + if (service.getApi().pollAIDecompileStatus(fID).getStatus() == AiDecompilationTaskStatus.UNINITIALISED) { // Trigger the decompilation service.getApi().triggerAIDecompilationForFunctionID(fID); } @@ -340,10 +341,8 @@ private void waitForDecomp(TypedApiInterface.FunctionID id, TaskMonitor monitor) monitor.setMessage("Waiting for AI Decompilation for %s ... Current status: %s".formatted(functionWithID.function().getName(), lastDecompStatus.getStatus())); monitor.checkCancelled(); switch (newStatus.getStatus()) { - case "pending": - case "uninitialised": - case "queued": - case "running": + case PENDING: + case UNINITIALISED: try { // Wait a second before polling again. We don't want to spam the API with requests too often Thread.sleep(1000); @@ -351,10 +350,10 @@ private void waitForDecomp(TypedApiInterface.FunctionID id, TaskMonitor monitor) throw new RuntimeException(e); } break; - case "success": + case SUCCESS: monitor.setProgress(monitor.getMaximum()); return; - case "error": + case ERROR: logger.error("Decompilation failed: %s".formatted(newStatus.getDecompilation())); return; default: diff --git a/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/GhidraRevengService.java b/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/GhidraRevengService.java index 320474f6..9966cf56 100644 --- a/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/GhidraRevengService.java +++ b/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/GhidraRevengService.java @@ -645,7 +645,7 @@ public String decompileFunctionViaAI(FunctionWithID functionWithID, TaskMonitor // Check if there is an existing process already, because the trigger API will fail with 400 if there is var fID = functionWithID.functionID; var function = functionWithID.function; - if (api.pollAIDecompileStatus(fID).getStatus().equals("uninitialised")){ + if (api.pollAIDecompileStatus(fID).getStatus() == AiDecompilationTaskStatus.UNINITIALISED){ // Trigger the decompilation api.triggerAIDecompilationForFunctionID(fID); } @@ -660,10 +660,8 @@ public String decompileFunctionViaAI(FunctionWithID functionWithID, TaskMonitor window.setDisplayedValuesBasedOnStatus(function, status); switch (status.getStatus()) { - case "pending": - case "uninitialised": - case "queued": - case "running": + case PENDING: + case UNINITIALISED: try { Thread.sleep(100); } catch (InterruptedException e) { @@ -671,11 +669,11 @@ public String decompileFunctionViaAI(FunctionWithID functionWithID, TaskMonitor } // monitor.incrementProgress(100); break; - case "success": + case SUCCESS: monitor.setProgress(monitor.getMaximum()); window.setDisplayedValuesBasedOnStatus(function, status); return status.getDecompilation(); - case "error": + case ERROR: return "Decompilation failed: %s".formatted(status.getStatus()); default: throw new RuntimeException("Unknown status: %s".formatted(status.getStatus())); diff --git a/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/TypedApiImplementation.java b/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/TypedApiImplementation.java index be660f5c..e21b76ec 100644 --- a/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/TypedApiImplementation.java +++ b/src/main/java/ai/reveng/toolkit/ghidra/core/services/api/TypedApiImplementation.java @@ -132,7 +132,7 @@ public BinaryHash upload(Path binPath) throws FileNotFoundException, ApiExceptio if (!bin.exists()) throw new FileNotFoundException("Binary to upload does not exist"); - var result = this.analysisCoreApi.uploadFile(UploadFileType.fromValue("BINARY"), bin, null, true); + var result = this.analysisCoreApi.uploadFile(UploadFileType.fromValue("BINARY"), bin.getAbsolutePath(), null, true); return new BinaryHash(result.getData().getSha256Hash()); } @@ -228,7 +228,7 @@ public List getFunctionInfo(AnalysisID analysisID) { BaseResponseAnalysisFunctions response = null; try { - response = this.analysesResultsMetadataApi.getFunctionsList(analysisID.id(), null, null, null); + response = this.analysesResultsMetadataApi.getFunctionsList(analysisID.id(), null, null, null, false, null, null); } catch (ApiException e) { throw new RuntimeException("Could not find analysis with ID: " + analysisID.id(), e); } @@ -468,7 +468,8 @@ public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) { var response = functionsAiDecompilationApi.getAiDecompilationTaskResult( functionID.value(), // Long functionId true, // summarise - true // generateInlineComments + true, // generateInlineComments + null // forceRegenerate ); return response.getData(); } catch (ApiException e) { diff --git a/src/test/java/ai/reveng/AIDecompilerComponentTest.java b/src/test/java/ai/reveng/AIDecompilerComponentTest.java index 548efd0c..f8b1356e 100644 --- a/src/test/java/ai/reveng/AIDecompilerComponentTest.java +++ b/src/test/java/ai/reveng/AIDecompilerComponentTest.java @@ -1,6 +1,7 @@ package ai.reveng; import ai.reveng.invoker.ApiException; +import ai.reveng.model.AiDecompilationTaskStatus; import ai.reveng.model.GetAiDecompilationTask; import ai.reveng.toolkit.ghidra.binarysimilarity.ui.aidecompiler.AIDecompilationdWindow; import ai.reveng.toolkit.ghidra.core.services.api.AnalysisOptionsBuilder; @@ -63,7 +64,7 @@ public List getFunctionInfo(AnalysisID analysisID) { public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) { if (functionID.value() == 2) { return new GetAiDecompilationTask() - .status("success") + .status(AiDecompilationTaskStatus.SUCCESS) .decompilation("int func2(int a) { return a + 1; }") .rawDecompilation("int func2(int a) { return a + 1; }") .summary("Mocked Description Summary for func2") @@ -71,7 +72,7 @@ public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) { .rawAiSummary("Summary for func2"); } else if (functionID.value() == 1) { return new GetAiDecompilationTask() - .status("success") + .status(AiDecompilationTaskStatus.SUCCESS) .decompilation("void func1() { return; }") .rawDecompilation("void func1() { return; }") .summary("Mocked Description Summary") @@ -225,7 +226,7 @@ public List getFunctionInfo(AnalysisID analysisID) { @Override public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) { return new GetAiDecompilationTask() - .status("success") + .status(AiDecompilationTaskStatus.SUCCESS) .decompilation("void func1() { return; }") .rawDecompilation("void func1() { return; }") .summary("Mocked Description Summary")