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 <paul.khattu@gmail.com>
This commit is contained in:
Pavel Khattu 2025-03-27 12:11:38 +01:00 committed by GitHub
parent 566a065ca3
commit 3983b39dd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 36 additions and 6 deletions

View file

@ -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();

View file

@ -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() {

View file

@ -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);
}
}