Skip to content

Commit 02b25a8

Browse files
authored
Skip LLM codemods when no service is available (#418)
1 parent af04044 commit 02b25a8

File tree

5 files changed

+62
-16
lines changed

5 files changed

+62
-16
lines changed
Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package io.codemodder.plugins.llm;
22

33
import com.google.inject.AbstractModule;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
46

57
/** Provides configured LLM services. */
68
public final class LLMServiceModule extends AbstractModule {
79

810
private static final String OPENAI_KEY_NAME = "CODEMODDER_OPENAI_API_KEY";
911
private static final String AZURE_OPENAI_KEY_NAME = "CODEMODDER_AZURE_OPENAI_API_KEY";
1012
private static final String AZURE_OPENAI_ENDPOINT = "CODEMODDER_AZURE_OPENAI_ENDPOINT";
13+
private static final Logger logger = LoggerFactory.getLogger(LLMServiceModule.class);
1114

1215
@Override
1316
protected void configure() {
@@ -22,19 +25,20 @@ protected void configure() {
2225
+ " must be set");
2326
}
2427
if (azureOpenAIKey != null) {
28+
logger.info("Using Azure OpenAI service with endpoint {}", azureOpenAIEndpoint);
2529
bind(OpenAIService.class)
2630
.toProvider(() -> OpenAIService.fromAzureOpenAI(azureOpenAIKey, azureOpenAIEndpoint));
2731
return;
2832
}
2933

30-
bind(OpenAIService.class).toProvider(() -> OpenAIService.fromOpenAI(getOpenAIToken()));
31-
}
32-
33-
private String getOpenAIToken() {
3434
final var openAIKey = System.getenv(OPENAI_KEY_NAME);
35-
if (openAIKey == null) {
36-
throw new IllegalArgumentException(OPENAI_KEY_NAME + " environment variable must be set");
35+
if (openAIKey != null) {
36+
logger.info("Using OpenAI service");
37+
bind(OpenAIService.class).toProvider(() -> OpenAIService.fromOpenAI(openAIKey));
38+
return;
3739
}
38-
return openAIKey;
40+
41+
logger.info("No LLM service available");
42+
bind(OpenAIService.class).toProvider(OpenAIService::noServiceAvailable);
3943
}
4044
}

plugins/codemodder-plugin-llm/src/main/java/io/codemodder/plugins/llm/OpenAIService.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class OpenAIService {
2121
private final OpenAIClient api;
2222
private static final int TIMEOUT_SECONDS = 90;
2323
private final ModelMapper modelMapper;
24+
private boolean serviceAvailable = true;
2425

2526
private static OpenAIClientBuilder builder(final KeyCredential key) {
2627
HttpClientOptions clientOptions = new HttpClientOptions();
@@ -31,6 +32,12 @@ private static OpenAIClientBuilder builder(final KeyCredential key) {
3132
.credential(key);
3233
}
3334

35+
OpenAIService(final boolean serviceAvailable) {
36+
this.serviceAvailable = serviceAvailable;
37+
this.modelMapper = null;
38+
this.api = null;
39+
}
40+
3441
OpenAIService(final ModelMapper mapper, final KeyCredential key) {
3542
this.modelMapper = mapper;
3643
this.api = builder(key).buildClient();
@@ -66,6 +73,19 @@ public static OpenAIService fromAzureOpenAI(final String token, final String end
6673
Objects.requireNonNull(endpoint));
6774
}
6875

76+
public static OpenAIService noServiceAvailable() {
77+
return new OpenAIService(false);
78+
}
79+
80+
/**
81+
* Returns whether the service is available.
82+
*
83+
* @return whether the service is available
84+
*/
85+
public boolean isServiceAvailable() {
86+
return serviceAvailable;
87+
}
88+
6989
/**
7090
* Gets the completion for the given messages.
7191
*
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.codemodder.plugins.llm;
2+
3+
import io.codemodder.RuleSarif;
4+
import io.codemodder.SarifPluginRawFileChanger;
5+
import java.util.Objects;
6+
7+
/** A base class for LLM codemods that process SARIF and use the OpenAI service. */
8+
public abstract class SarifPluginLLMCodemod extends SarifPluginRawFileChanger {
9+
protected final OpenAIService openAI;
10+
11+
public SarifPluginLLMCodemod(RuleSarif sarif, final OpenAIService openAI) {
12+
super(sarif);
13+
this.openAI = Objects.requireNonNull(openAI);
14+
}
15+
16+
/**
17+
* Indicates whether the codemod should run.
18+
*
19+
* <p>Subclasses can override this method to add additional hecks but should call
20+
* super.shouldRun() to ensure the OpenAI service is available.
21+
*/
22+
@Override
23+
public boolean shouldRun() {
24+
return openAI.isServiceAvailable();
25+
}
26+
}

plugins/codemodder-plugin-llm/src/main/java/io/codemodder/plugins/llm/SarifToLLMForBinaryVerificationAndFixingCodemod.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,13 @@
3030
* </ol>
3131
*/
3232
public abstract class SarifToLLMForBinaryVerificationAndFixingCodemod
33-
extends SarifPluginRawFileChanger {
33+
extends SarifPluginLLMCodemod {
3434

35-
private final OpenAIService openAI;
3635
private final Model model;
3736

3837
protected SarifToLLMForBinaryVerificationAndFixingCodemod(
3938
final RuleSarif sarif, final OpenAIService openAI, final Model model) {
40-
super(sarif);
41-
this.openAI = Objects.requireNonNull(openAI);
39+
super(sarif, openAI);
4240
this.model = Objects.requireNonNull(model);
4341
}
4442

plugins/codemodder-plugin-llm/src/main/java/io/codemodder/plugins/llm/SarifToLLMForMultiOutcomeCodemod.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@
3838
* <p>To accomplish that, we need the analysis to "bucket" the code into one of the above
3939
* categories.
4040
*/
41-
public abstract class SarifToLLMForMultiOutcomeCodemod extends SarifPluginRawFileChanger {
41+
public abstract class SarifToLLMForMultiOutcomeCodemod extends SarifPluginLLMCodemod {
4242

4343
private static final Logger logger =
4444
LoggerFactory.getLogger(SarifToLLMForMultiOutcomeCodemod.class);
45-
private final OpenAIService openAI;
4645
private final List<LLMRemediationOutcome> remediationOutcomes;
4746
private final Model categorizationModel;
4847
private final Model codeChangingModel;
@@ -65,8 +64,7 @@ protected SarifToLLMForMultiOutcomeCodemod(
6564
final List<LLMRemediationOutcome> remediationOutcomes,
6665
final Model categorizationModel,
6766
final Model codeChangingModel) {
68-
super(sarif);
69-
this.openAI = Objects.requireNonNull(openAI);
67+
super(sarif, openAI);
7068
this.remediationOutcomes = Objects.requireNonNull(remediationOutcomes);
7169
if (remediationOutcomes.size() < 2) {
7270
throw new IllegalArgumentException("must have 2+ remediation outcome");
@@ -78,7 +76,7 @@ protected SarifToLLMForMultiOutcomeCodemod(
7876
@Override
7977
public CodemodFileScanningResult onFileFound(
8078
final CodemodInvocationContext context, final List<Result> results) {
81-
logger.info("processing: {}", context.path());
79+
logger.debug("processing: {}", context.path());
8280

8381
List<CodemodChange> changes = new ArrayList<>();
8482
for (Result result : results) {

0 commit comments

Comments
 (0)