From 3983b39dd12ff5509ae9deeea8cbb0c438794bc7 Mon Sep 17 00:00:00 2001 From: Pavel Khattu Date: Thu, 27 Mar 2025 12:11:38 +0100 Subject: [PATCH] feat: custom base host support for anthropic provider (#948) * Add support for custom baseHost for Anthropic provider https://github.com/carlrobertoh/ProxyAI/issues/697 * Use intellij-provided socket factory and trust manager for default client --------- Co-authored-by: borgotta --- .../completions/CompletionClientProvider.java | 15 +++++++++++---- .../anthropic/AnthropicSettingsForm.java | 8 ++++++++ .../anthropic/AnthropicSettingsState.java | 19 +++++++++++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java index b91b96c6..f8401ebd 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java @@ -3,6 +3,7 @@ package ee.carlrobert.codegpt.completions; import static ee.carlrobert.codegpt.credentials.CredentialsStore.getCredential; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.util.net.ssl.CertificateManager; import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.settings.advanced.AdvancedSettings; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings; @@ -21,6 +22,7 @@ import ee.carlrobert.llm.client.openai.OpenAIClient; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.concurrent.TimeUnit; +import javax.net.ssl.X509TrustManager; import okhttp3.Credentials; import okhttp3.OkHttpClient; @@ -39,10 +41,12 @@ public class CompletionClientProvider { } public static ClaudeClient getClaudeClient() { - return new ClaudeClient( - getCredential(CredentialKey.AnthropicApiKey.INSTANCE), - AnthropicSettings.getCurrentState().getApiVersion(), - getDefaultClientBuilder()); + var builder = new ClaudeClient.Builder(getCredential(CredentialKey.AnthropicApiKey.INSTANCE), + AnthropicSettings.getCurrentState().getApiVersion()); + if (AnthropicSettings.getCurrentState().hasCustomBaseHost()) { + builder.setHost(AnthropicSettings.getCurrentState().getBaseHost()); + } + return builder.build(getDefaultClientBuilder()); } public static AzureClient getAzureClient() { @@ -96,6 +100,9 @@ public class CompletionClientProvider { public static OkHttpClient.Builder getDefaultClientBuilder() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); + CertificateManager certificateManager = CertificateManager.getInstance(); + X509TrustManager trustManager = certificateManager.getTrustManager(); + builder.sslSocketFactory(certificateManager.getSslContext().getSocketFactory(), trustManager); var advancedSettings = AdvancedSettings.getCurrentState(); var proxyHost = advancedSettings.getProxyHost(); var proxyPort = advancedSettings.getProxyPort(); diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsForm.java b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsForm.java index 9039e1bc..836979bf 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsForm.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsForm.java @@ -17,6 +17,7 @@ public class AnthropicSettingsForm { private final JBPasswordField apiKeyField; private final JBTextField apiVersionField; private final JBTextField modelField; + private final JBTextField baseHostField; public AnthropicSettingsForm(AnthropicSettingsState settings) { apiKeyField = new JBPasswordField(); @@ -29,6 +30,7 @@ public class AnthropicSettingsForm { }); apiVersionField = new JBTextField(settings.getApiVersion(), 35); modelField = new JBTextField(settings.getModel(), 35); + baseHostField = new JBTextField(settings.getBaseHost(), 35); } public JPanel getForm() { @@ -51,6 +53,10 @@ public class AnthropicSettingsForm { .withComment(CodeGPTBundle.get( "settingsConfigurable.service.anthropic.model.comment")) .resizeX(false)) + .add(UI.PanelFactory.panel(baseHostField) + .withLabel(CodeGPTBundle.get("settingsConfigurable.shared.baseHost.label")) + .withComment("Optional: Custom API endpoint (e.g., https://api.anthropic.com)") + .resizeX(false)) .createPanel()) .addComponentFillVertically(new JPanel(), 0) .getPanel(); @@ -60,6 +66,7 @@ public class AnthropicSettingsForm { var state = new AnthropicSettingsState(); state.setModel(modelField.getText()); state.setApiVersion(apiVersionField.getText()); + state.setBaseHost(baseHostField.getText()); return state; } @@ -70,6 +77,7 @@ public class AnthropicSettingsForm { ); apiVersionField.setText(state.getApiVersion()); modelField.setText(state.getModel()); + baseHostField.setText(state.getBaseHost()); } public @Nullable String getApiKey() { diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsState.java b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsState.java index ddaa7794..aaff7041 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsState.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettingsState.java @@ -6,6 +6,7 @@ public class AnthropicSettingsState { private String apiVersion = "2023-06-01"; private String model = "claude-3-opus-20240229"; + private String baseHost = ""; public String getApiVersion() { return apiVersion; @@ -23,6 +24,18 @@ public class AnthropicSettingsState { this.model = model; } + public String getBaseHost() { + return baseHost; + } + + public void setBaseHost(String baseHost) { + this.baseHost = baseHost; + } + + public boolean hasCustomBaseHost() { + return baseHost != null && !baseHost.trim().isEmpty(); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -32,11 +45,13 @@ public class AnthropicSettingsState { return false; } AnthropicSettingsState that = (AnthropicSettingsState) o; - return Objects.equals(apiVersion, that.apiVersion) && Objects.equals(model, that.model); + return Objects.equals(apiVersion, that.apiVersion) + && Objects.equals(model, that.model) + && Objects.equals(baseHost, that.baseHost); } @Override public int hashCode() { - return Objects.hash(apiVersion, model); + return Objects.hash(apiVersion, model, baseHost); } }